]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Sync up with TLS/X.509 changes in libcups v3.
authorMichael R Sweet <msweet@msweet.org>
Tue, 18 Jun 2024 15:09:04 +0000 (11:09 -0400)
committerMichael R Sweet <msweet@msweet.org>
Tue, 18 Jun 2024 15:09:04 +0000 (11:09 -0400)
Sync up with userconfig/sysconfig changes in libcups v3.

15 files changed:
backend/ipp.c
cups/adminutil.c
cups/cups-private.h
cups/cups.h
cups/dest.c
cups/globals.c
cups/ppd-util.c
cups/snmp.c
cups/testcreds.c
cups/testhttp.c
cups/tls-gnutls.c
cups/tls-openssl.c
cups/tls.c
cups/usersys.c
systemv/lpstat.c

index 3b861be029668339d12b088a10af98907d360ce5..0e658690074e5ed58c282b36d218744a58400220 100644 (file)
@@ -812,7 +812,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
     if ((creds = httpCopyPeerCredentials(http)) != NULL)
     {
-      trust = cupsGetCredentialsTrust(NULL, hostname, creds);
+      trust = cupsGetCredentialsTrust(NULL, hostname, creds, /*require_ca*/false);
       cupsGetCredentialsInfo(creds, credinfo, sizeof(credinfo));
 
       fprintf(stderr, "DEBUG: %s (%s)\n", trust_msgs[trust], cupsGetErrorString());
index 8c2ceb2594eb81a7d8d20e306ccbf80933c6797d..448164a366afc12bb5da622f77277c80f67a6ce3 100644 (file)
@@ -1368,7 +1368,7 @@ get_cupsd_conf(
   if (_cups_strcasecmp(cg->cupsd_hostname, host))
     invalidate_cupsd_cache(cg);
 
-  snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot);
+  snprintf(name, namesize, "%s/cupsd.conf", cg->sysconfig);
   *remote = 0;
 
 #ifndef _WIN32
index bbf1c74ae2f4e1a067c594a02a71788b8a1023f5..b3275217c72d3fd62a985de99061447de4d6eba4 100644 (file)
@@ -69,10 +69,9 @@ typedef struct _cups_globals_s               // CUPS global state data
   // Multiple places...
   const char           *cups_datadir,  // CUPS_DATADIR environment var
                        *cups_serverbin,// CUPS_SERVERBIN environment var
-                       *cups_serverroot,
-                                       // CUPS_SERVERROOT environment var
+                       *sysconfig,     // System configuration directory (influenced by CUPS_SERVERROOT environment var)
                        *cups_statedir, // CUPS_STATEDIR environment var
-                       *home,          // HOME environment var
+                       *userconfig,    // User configuration directory (influenced by various environment vars)
                        *localedir;     // LOCALDIR environment var
 
   // adminutil.c
@@ -190,7 +189,6 @@ typedef struct _cups_globals_s              // CUPS global state data
   char                 pw_buf[PW_BUF_SIZE];
                                        // Big buffer for struct passwd buffers
 #  endif // !_WIN32
-  const char           *userconfig;    // User-specific config files
 } _cups_globals_t;
 
 typedef struct _cups_media_db_s                // Media database
index b0f15ca5f16c1f18358be9f0f418175d9d35a45f..8e527a2e9ff28f16a6e0db31acd21282a032634d 100644 (file)
@@ -430,7 +430,7 @@ extern void         cupsFreeOptions(int num_options, cups_option_t *options) _CUPS_PUBL
 extern int             cupsGetClasses(char ***classes) _CUPS_DEPRECATED_MSG("Use cupsEnumDests instead.");
 extern time_t          cupsGetCredentialsExpiration(const char *credentials) _CUPS_PUBLIC;
 extern char            *cupsGetCredentialsInfo(const char *credentials, char *buffer, size_t bufsize) _CUPS_PUBLIC;
-extern http_trust_t    cupsGetCredentialsTrust(const char *path, const char *common_name, const char *credentials) _CUPS_PUBLIC;
+extern http_trust_t    cupsGetCredentialsTrust(const char *path, const char *common_name, const char *credentials, bool require_ca) _CUPS_PUBLIC;
 extern const char      *cupsGetDefault(void) _CUPS_PUBLIC;
 extern const char      *cupsGetDefault2(http_t *http) _CUPS_PUBLIC;
 extern cups_dest_t     *cupsGetDest(const char *name, const char *instance, int num_dests, cups_dest_t *dests) _CUPS_PUBLIC;
index 8e0713f4ed9182e6afb861ba35d64d5348b66ff8..69708579e34a2d8f88eb8970423ba3698591721f 100644 (file)
@@ -1694,17 +1694,13 @@ cupsGetNamedDest(http_t     *http,      // I - Connection to server or @code CUPS_HTT
       else
         instance = NULL;
     }
-    else if (cg->home)
+    else if (cg->userconfig)
     {
      /*
       * No default in the environment, try the user's lpoptions files...
       */
 
-#if _WIN32
-      snprintf(filename, sizeof(filename), "%s/AppData/Local/cups/lpoptions", cg->home);
-#else
-      snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
-#endif // _WIN32
+      snprintf(filename, sizeof(filename), "%s/lpoptions", cg->userconfig);
 
       dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
 
@@ -1718,7 +1714,7 @@ cupsGetNamedDest(http_t     *http,        // I - Connection to server or @code CUPS_HTT
       * Still not there?  Try the system lpoptions file...
       */
 
-      snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+      snprintf(filename, sizeof(filename), "%s/lpoptions", cg->sysconfig);
       dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
 
       if (dest_name)
@@ -1806,16 +1802,12 @@ cupsGetNamedDest(http_t     *http,      // I - Connection to server or @code CUPS_HTT
   // Then add local options...
   //
 
-  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->sysconfig);
   cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest);
 
-  if (cg->home)
+  if (cg->userconfig)
   {
-#if _WIN32
-    snprintf(filename, sizeof(filename), "%s/AppData/Local/cups/lpoptions", cg->home);
-#else
-    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
-#endif // _WIN32
+    snprintf(filename, sizeof(filename), "%s/lpoptions", cg->userconfig);
 
     cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest);
   }
@@ -1984,9 +1976,9 @@ cupsSetDests2(http_t      *http,  // I - Connection to server or @code CUPS_HTTP_
   // Figure out which file to write to...
   //
 
-  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->sysconfig);
 
-  if (cg->home
+  if (cg->userconfig
 #ifndef _WIN32
       && getuid() != 0
 #endif // !_WIN32
@@ -1996,19 +1988,9 @@ cupsSetDests2(http_t      *http, // I - Connection to server or @code CUPS_HTTP_
     * Create ~/.cups subdirectory...
     */
 
-#if _WIN32
-    snprintf(filename, sizeof(filename), "%s/AppData/Local/cups", cg->home);
-#else
-    snprintf(filename, sizeof(filename), "%s/.cups", cg->home);
-#endif // _WIN32
-    if (access(filename, 0))
-      mkdir(filename, 0700);
+    mkdir(cg->userconfig, 0700);
 
-#if _WIN32
-    snprintf(filename, sizeof(filename), "%s/AppData/Local/cups/lpoptions", cg->home);
-#else
-    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
-#endif // _WIN32
+    snprintf(filename, sizeof(filename), "%s/lpoptions", cg->userconfig);
   }
 
   //
@@ -3109,17 +3091,12 @@ cups_enum_dests(
 
   user_default = _cupsGetUserDefault(data.def_name, sizeof(data.def_name));
 
-  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+  snprintf(filename, sizeof(filename), "%s/lpoptions", cg->sysconfig);
   data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests);
 
-  if (cg->home)
+  if (cg->userconfig)
   {
-  // TODO: Use cg->userconfig
-#if _WIN32
-    snprintf(filename, sizeof(filename), "%s/AppData/Local/cups/lpoptions", cg->home);
-#else
-    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
-#endif // _WIN32
+    snprintf(filename, sizeof(filename), "%s/lpoptions", cg->userconfig);
 
     data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests);
   }
index a72220a020fa14076a6dcddd85c105e344408a56..185b634f5452da89b340c4ebadea89febe423526 100644 (file)
@@ -174,14 +174,6 @@ cups_globals_alloc(void)
 {
   _cups_globals_t *cg = calloc(1, sizeof(_cups_globals_t));
                                        /* Pointer to global data */
-#ifdef _WIN32
-  HKEY         key;                    /* Registry key */
-  DWORD                size;                   /* Size of string */
-  static char  homedir[1024] = "",     /* Home directory */
-               installdir[1024] = "",  /* Install directory */
-               confdir[1024] = "",     /* Server root directory */
-               localedir[1024] = "";   /* Locale directory */
-#endif /* _WIN32 */
 
 
   if (!cg)
@@ -212,6 +204,13 @@ cups_globals_alloc(void)
   */
 
 #ifdef _WIN32
+  HKEY         key;                    /* Registry key */
+  DWORD                size;                   /* Size of string */
+  static char  installdir[1024] = "",  /* Install directory */
+               localedir[1024] = "",   /* Locale directory */
+               sysconfig[1024] = "",   /* Server configuration directory */
+               userconfig[1024] = "";  /* User configuration directory */
+
   if (!installdir[0])
   {
    /*
@@ -248,7 +247,7 @@ cups_globals_alloc(void)
       }
     }
 
-    snprintf(confdir, sizeof(confdir), "%s/conf", installdir);
+    snprintf(sysconfig, sizeof(sysconfig), "%s/conf", installdir);
     snprintf(localedir, sizeof(localedir), "%s/locale", installdir);
   }
 
@@ -258,8 +257,8 @@ cups_globals_alloc(void)
   if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
     cg->cups_serverbin = installdir;
 
-  if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
-    cg->cups_serverroot = confdir;
+  if ((cg->sysconfig = getenv("CUPS_SERVERROOT")) == NULL)
+    cg->sysconfig = confdir;
 
   if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
     cg->cups_statedir = confdir;
@@ -267,31 +266,36 @@ cups_globals_alloc(void)
   if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
     cg->localedir = localedir;
 
-  if (!homedir[0])
+  if (!userconfig[0])
   {
     const char *userprofile = getenv("USERPROFILE");
                                // User profile (home) directory
-    char       *homeptr;       // Pointer into homedir
+    char       *userptr;       // Pointer into userconfig
 
     DEBUG_printf("cups_globals_alloc: USERPROFILE=\"%s\"", userprofile);
 
-    if (!strncmp(userprofile, "C:\\", 3))
-      userprofile += 2;
-
-    cupsCopyString(homedir, userprofile, sizeof(homedir));
-    for (homeptr = homedir; *homeptr; homeptr ++)
+    snprintf(userconfig, sizeof(userconfig), "%s/AppData/Local/cups", userprofile);
+    for (userptr = userconfig; *userptr; userptr ++)
     {
       // Convert back slashes to forward slashes
-      if (*homeptr == '\\')
-        *homeptr = '/';
+      if (*userptr == '\\')
+        *userptr = '/';
     }
 
-    DEBUG_printf("cups_globals_alloc: homedir=\"%s\"", homedir);
+    DEBUG_printf("cups_globals_alloc: userconfig=\"%s\"", userconfig);
   }
 
-  cg->home = homedir;
+  cg->userconfig = userconfig;
 
 #else
+  const char   *home = getenv("HOME"); // HOME environment variable
+  char         homedir[1024],          // Home directory from account
+               temp[1024];             // Temporary directory string
+#  ifndef __APPLE__
+  const char   *snap_common = getenv("SNAP_COMMON"),
+               *xdg_config_home = getenv("XDG_CONFIG_HOME");
+                                       // Environment variables
+#  endif // !__APPLE__
 #  ifdef HAVE_GETEUID
   if ((geteuid() != getuid() && getuid()) || getegid() != getgid())
 #  else
@@ -305,7 +309,7 @@ cups_globals_alloc(void)
 
     cg->cups_datadir    = CUPS_DATADIR;
     cg->cups_serverbin  = CUPS_SERVERBIN;
-    cg->cups_serverroot = CUPS_SERVERROOT;
+    cg->sysconfig       = CUPS_SERVERROOT;
     cg->cups_statedir   = CUPS_STATEDIR;
     cg->localedir       = CUPS_LOCALEDIR;
   }
@@ -321,32 +325,73 @@ cups_globals_alloc(void)
     if ((cg->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
       cg->cups_serverbin = CUPS_SERVERBIN;
 
-    if ((cg->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL)
-      cg->cups_serverroot = CUPS_SERVERROOT;
+    if ((cg->sysconfig = getenv("CUPS_SERVERROOT")) == NULL)
+      cg->sysconfig = CUPS_SERVERROOT;
 
     if ((cg->cups_statedir = getenv("CUPS_STATEDIR")) == NULL)
       cg->cups_statedir = CUPS_STATEDIR;
 
     if ((cg->localedir = getenv("LOCALEDIR")) == NULL)
       cg->localedir = CUPS_LOCALEDIR;
-
-    cg->home = getenv("HOME");
-
-#  ifdef __APPLE__ /* Sandboxing now exposes the container as the home directory */
-    if (cg->home && strstr(cg->home, "/Library/Containers/"))
-      cg->home = NULL;
-#  endif /* !__APPLE__ */
   }
 
-  if (!cg->home)
+#  ifdef __APPLE__
+  if (!home)
+#else
+  if (!home && !xdg_config_home)
+#  endif // __APPLE__
+  if (!home)
   {
     struct passwd      pw;             /* User info */
     struct passwd      *result;        /* Auxiliary pointer */
 
     getpwuid_r(getuid(), &pw, cg->pw_buf, PW_BUF_SIZE, &result);
     if (result)
-      cg->home = _cupsStrAlloc(pw.pw_dir);
+    {
+      cupsCopyString(homedir, pw.pw_dir, sizeof(homedir));
+      home = homedir;
+    }
+  }
+
+#  ifdef __APPLE__
+  if (home)
+  {
+    // macOS uses ~/Library/Application Support/FOO
+    snprintf(temp, sizeof(temp), "%s/Library/Application Support/cups", home);
   }
+  else
+  {
+    // Something went wrong, use temporary directory...
+    snprintf(temp, sizeof(temp), "/private/tmp/cups%u", (unsigned)getuid());
+  }
+
+#  else
+  if (snap_common)
+  {
+    // Snaps use $SNAP_COMMON/FOO
+    snprintf(temp, sizeof(temp), "%s/cups", snap_common);
+  }
+  else if (xdg_config_home)
+  {
+    // XDG uses $XDG_CONFIG_HOME/FOO
+    snprintf(temp, sizeof(temp), "%s/cups", xdg_config_home);
+  }
+  else if (home)
+  {
+    // Use ~/.cups if it exists, otherwise ~/.config/cups (XDG standard)
+    snprintf(temp, sizeof(temp), "%s/.cups", home);
+    if (access(temp, 0))
+      snprintf(temp, sizeof(temp), "%s/.config/cups", home);
+  }
+  else
+  {
+    // Something went wrong, use temporary directory...
+    snprintf(temp, sizeof(temp), "/tmp/cups%u", (unsigned)getuid());
+  }
+#  endif // __APPLE__
+
+  // Can't use _cupsStrAlloc since it causes a loop with debug logging enabled
+  cg->userconfig = strdup(temp);
 #endif /* _WIN32 */
 
   return (cg);
@@ -388,8 +433,8 @@ cups_globals_free(_cups_globals_t *cg)      /* I - Pointer to global data */
 
   cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
 
-  if (cg->raster_error.start)
-    free(cg->raster_error.start);
+  free(cg->userconfig);
+  free(cg->raster_error.start);
 
   free(cg);
 }
index 531db8631462bd2cb307a0a403d50b8a81d995f7..ca55f97b1a6e44d4f48c65d8e08b8c245fe869f2 100644 (file)
@@ -188,7 +188,7 @@ cupsGetPPD3(http_t     *http,               /* I  - HTTP connection or @code CUPS_HTTP_DEFAUL
     struct stat        ppdinfo;                /* PPD file information */
 
 
-    snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd", cg->cups_serverroot,
+    snprintf(ppdname, sizeof(ppdname), "%s/ppd/%s.ppd", cg->sysconfig,
              name);
     if (!stat(ppdname, &ppdinfo) && !access(ppdname, R_OK))
     {
index 3d68a5e424088d1c2d7cf07193706d0a1c8810a8..8aff0329f7965ea042b7c449f087b7c35975dd44 100644 (file)
@@ -123,7 +123,7 @@ _cupsSNMPDefaultCommunity(void)
   {
     cupsCopyString(cg->snmp_community, "public", sizeof(cg->snmp_community));
 
-    snprintf(line, sizeof(line), "%s/snmp.conf", cg->cups_serverroot);
+    snprintf(line, sizeof(line), "%s/snmp.conf", cg->sysconfig);
     if ((fp = cupsFileOpen(line, "r")) != NULL)
     {
       linenum = 0;
index e393ee00f4d0859789b156cfd973b839e11f61cb..5018df874c815ee5ab04c5b8639d15e66b601e23 100644 (file)
@@ -702,7 +702,7 @@ test_client(const char *uri)                // I - URI
   puts("TLS Server Credentials:");
   if ((hcreds = httpCopyPeerCredentials(http)) != NULL)
   {
-    trust = cupsGetCredentialsTrust(TEST_CERT_PATH, hostname, hcreds);
+    trust = cupsGetCredentialsTrust(TEST_CERT_PATH, hostname, hcreds, /*require_ca*/false);
 
     cupsGetCredentialsInfo(hcreds, hinfo, sizeof(hinfo));
 
index 77a42727715b6467a0a43e078d4fc20f34ac2ea7..98dbe4acabb89fc2f5eb3f89c4361422b5b9aa60 100644 (file)
@@ -1,7 +1,7 @@
 //
 // HTTP test program for CUPS.
 //
-// Copyright Â© 2020-2024 by OpenPrinting.
+// Copyright Â© 2021-2024 by OpenPrinting.
 // Copyright Â© 2007-2018 by Apple Inc.
 // Copyright Â© 1997-2006 by Easy Software Products.
 //
@@ -558,7 +558,7 @@ main(int  argc,                             // I - Number of command-line arguments
 
   // Test HTTP GET requests...
   http = NULL;
-  out = stdout;
+  out  = stdout;
 
   for (i = 1; i < argc; i ++)
   {
@@ -600,7 +600,7 @@ main(int  argc,                             // I - Number of command-line arguments
       if ((creds = httpCopyPeerCredentials(http)) != NULL)
       {
        char *lcreds;
-        http_trust_t trust = cupsGetCredentialsTrust(NULL, hostname, creds);
+        http_trust_t trust = cupsGetCredentialsTrust(NULL, hostname, creds, /*require_ca*/true);
 
         cupsGetCredentialsInfo(creds, info, sizeof(info));
 
@@ -637,8 +637,9 @@ main(int  argc,                             // I - Number of command-line arguments
         if (trust != HTTP_TRUST_OK)
        {
          printf("SaveCredentials: %s\n", cupsSaveCredentials(NULL, hostname, creds, /*key*/NULL) ? "true" : "false");
-         trust = cupsGetCredentialsTrust(NULL, hostname, creds);
+         trust = cupsGetCredentialsTrust(NULL, hostname, creds, /*require_ca*/true);
          printf("New Trust: %s\n", trusts[trust]);
+         printf("SaveCredentials (NULL): %s\n", cupsSaveCredentials(NULL, hostname, /*creds*/NULL, /*key*/NULL) ? "true" : "false");
        }
 
         free(creds);
@@ -656,6 +657,7 @@ main(int  argc,                             // I - Number of command-line arguments
 
     do
     {
+      puts("Sending HEAD request...");
       if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
       {
        httpClearFields(http);
@@ -673,7 +675,7 @@ main(int  argc,                             // I - Number of command-line arguments
       httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http));
       httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
 
-      if (httpWriteRequest(http, "HEAD", resource))
+      if (!httpWriteRequest(http, "HEAD", resource))
       {
         if (!httpReconnect2(http, 30000, NULL))
         {
@@ -749,6 +751,7 @@ main(int  argc,                             // I - Number of command-line arguments
 
     do
     {
+      puts("Sending GET request...");
       if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close"))
       {
        httpClearFields(http);
@@ -767,7 +770,7 @@ main(int  argc,                             // I - Number of command-line arguments
       httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
       httpSetField(http, HTTP_FIELD_ACCEPT_ENCODING, encoding);
 
-      if (httpWriteRequest(http, "GET", resource))
+      if (!httpWriteRequest(http, "GET", resource))
       {
         if (!httpReconnect2(http, 30000, NULL))
         {
index 87d493b1eced9d08647efcafbe14a7af65dca638..65e07b58ffed70def2d2f540d16d288ae5a6cd09 100644 (file)
@@ -1,7 +1,9 @@
 //
 // TLS support code for CUPS using GNU TLS.
 //
-// Copyright Â© 2020-2023 by OpenPrinting
+// Note: This file is included from tls.c
+//
+// Copyright Â© 2020-2024 by OpenPrinting
 // Copyright Â©Â 2007-2019 by Apple Inc.
 // Copyright Â©Â 1997-2007 by Easy Software Products, all rights reserved.
 //
@@ -9,9 +11,6 @@
 // information.
 //
 
-//// This file is included from tls.c
-
-
 //
 // Local functions...
 //
@@ -764,12 +763,37 @@ cupsGetCredentialsInfo(
 //
 // 'cupsGetCredentialsTrust()' - Return the trust of credentials.
 //
+// This function determines the level of trust for the supplied credentials.
+// The "path" parameter specifies the certificate/key store for known
+// credentials and certificate authorities.  The "common_name" parameter
+// specifies the FQDN of the service being accessed such as
+// "printer.example.com".  The "credentials" parameter provides the credentials
+// being evaluated, which are usually obtained with the
+// @link httpCopyPeerCredentials@ function.  The "require_ca" parameter
+// specifies whether a CA-signed certificate is required for trust.
+//
+// The `AllowAnyRoot`, `AllowExpiredCerts`, `TrustOnFirstUse`, and
+// `ValidateCerts` options in the "client.conf" file (or corresponding
+// preferences file on macOS) control the trust policy, which defaults to
+// AllowAnyRoot=Yes, AllowExpiredCerts=No, TrustOnFirstUse=Yes, and
+// ValidateCerts=No.  When the "require_ca" parameter is `true` the AllowAnyRoot
+// and TrustOnFirstUse policies are turned off ("No").
+//
+// The returned trust value can be one of the following:
+//
+// - `HTTP_TRUST_OK`: Credentials are OK/trusted
+// - `HTTP_TRUST_INVALID`: Credentials are invalid
+// - `HTTP_TRUST_EXPIRED`: Credentials are expired
+// - `HTTP_TRUST_RENEWED`: Credentials have been renewed
+// - `HTTP_TRUST_UNKNOWN`: Credentials are unknown/new
+//
 
 http_trust_t                           // O - Level of trust
 cupsGetCredentialsTrust(
     const char *path,                  // I - Directory path for certificate/key store or `NULL` for default
     const char *common_name,           // I - Common name for trust lookup
-    const char *credentials)           // I - Credentials
+    const char *credentials,           // I - Credentials
+    bool       require_ca)             // I - Require a CA-signed certificate?
 {
   http_trust_t         trust = HTTP_TRUST_OK;
                                        // Trusted?
@@ -817,7 +841,7 @@ cupsGetCredentialsTrust(
     {
       // Credentials don't match, let's look at the expiration date of the new
       // credentials and allow if the new ones have a later expiration...
-      if (!cg->trust_first)
+      if (!cg->trust_first || require_ca)
       {
         // Do not trust certificates on first use...
         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
@@ -849,12 +873,12 @@ cupsGetCredentialsTrust(
 
     free(tcreds);
   }
-  else if (cg->validate_certs && !cupsAreCredentialsValidForName(common_name, credentials))
+  else if ((cg->validate_certs || require_ca) && !cupsAreCredentialsValidForName(common_name, credentials))
   {
     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1);
     trust = HTTP_TRUST_INVALID;
   }
-  else if (!cg->trust_first)
+  else if (num_certs > 1 && !http_check_roots(credentials))
   {
     // See if we have a site CA certificate we can compare...
     if ((tcreds = cupsCopyCredentials(path, "_site_")) != NULL)
@@ -877,11 +901,21 @@ cupsGetCredentialsTrust(
 
       free(tcreds);
     }
-    else
+    else if (require_ca)
     {
       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
       trust = HTTP_TRUST_INVALID;
     }
+    else if (!cg->trust_first)
+    {
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
+      trust = HTTP_TRUST_INVALID;
+    }
+  }
+  else if ((!cg->any_root || require_ca) && num_certs == 1)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1);
+    trust = HTTP_TRUST_INVALID;
   }
 
   if (trust == HTTP_TRUST_OK && !cg->expired_certs)
@@ -896,12 +930,6 @@ cupsGetCredentialsTrust(
     }
   }
 
-  if (trust == HTTP_TRUST_OK && !cg->any_root && num_certs == 1)
-  {
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1);
-    trust = HTTP_TRUST_INVALID;
-  }
-
   gnutls_free_certs(num_certs, certs);
 
   return (trust);
index bf5819dc018a09b9587dd1866f84f49b16bc58f3..ff0eccf4b8020463c1a919d8bfb8ef4bcee6794a 100644 (file)
@@ -736,12 +736,37 @@ cupsGetCredentialsInfo(
 //
 // 'cupsGetCredentialsTrust()' - Return the trust of credentials.
 //
+// This function determines the level of trust for the supplied credentials.
+// The "path" parameter specifies the certificate/key store for known
+// credentials and certificate authorities.  The "common_name" parameter
+// specifies the FQDN of the service being accessed such as
+// "printer.example.com".  The "credentials" parameter provides the credentials
+// being evaluated, which are usually obtained with the
+// @link httpCopyPeerCredentials@ function.  The "require_ca" parameter
+// specifies whether a CA-signed certificate is required for trust.
+//
+// The `AllowAnyRoot`, `AllowExpiredCerts`, `TrustOnFirstUse`, and
+// `ValidateCerts` options in the "client.conf" file (or corresponding
+// preferences file on macOS) control the trust policy, which defaults to
+// AllowAnyRoot=Yes, AllowExpiredCerts=No, TrustOnFirstUse=Yes, and
+// ValidateCerts=No.  When the "require_ca" parameter is `true` the AllowAnyRoot
+// and TrustOnFirstUse policies are turned off ("No").
+//
+// The returned trust value can be one of the following:
+//
+// - `HTTP_TRUST_OK`: Credentials are OK/trusted
+// - `HTTP_TRUST_INVALID`: Credentials are invalid
+// - `HTTP_TRUST_EXPIRED`: Credentials are expired
+// - `HTTP_TRUST_RENEWED`: Credentials have been renewed
+// - `HTTP_TRUST_UNKNOWN`: Credentials are unknown/new
+//
 
 http_trust_t                           // O - Level of trust
 cupsGetCredentialsTrust(
     const char *path,                  // I - Directory path for certificate/key store or `NULL` for default
     const char *common_name,           // I - Common name for trust lookup
-    const char *credentials)           // I - Credentials
+    const char *credentials,           // I - Credentials
+    bool       require_ca)             // I - Require a CA-signed certificate?
 {
   http_trust_t         trust = HTTP_TRUST_OK;
                                        // Trusted?
@@ -790,7 +815,7 @@ cupsGetCredentialsTrust(
     {
       // Credentials don't match, let's look at the expiration date of the new
       // credentials and allow if the new ones have a later expiration...
-      if (!cg->trust_first)
+      if (!cg->trust_first || require_ca)
       {
         // Do not trust certificates on first use...
         _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
@@ -822,12 +847,12 @@ cupsGetCredentialsTrust(
 
     free(tcreds);
   }
-  else if (cg->validate_certs && !cupsAreCredentialsValidForName(common_name, credentials))
+  else if ((cg->validate_certs || require_ca) && !cupsAreCredentialsValidForName(common_name, credentials))
   {
     _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No stored credentials, not valid for name."), 1);
     trust = HTTP_TRUST_INVALID;
   }
-  else if (!cg->trust_first)
+  else if (sk_X509_num(certs) > 1 && !http_check_roots(credentials))
   {
     // See if we have a site CA certificate we can compare...
     if ((tcreds = cupsCopyCredentials(path, "_site_")) != NULL)
@@ -850,12 +875,22 @@ cupsGetCredentialsTrust(
 
       free(tcreds);
     }
-    else
+    else if (require_ca)
+    {
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
+      trust = HTTP_TRUST_INVALID;
+    }
+    else if (!cg->trust_first)
     {
       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Trust on first use is disabled."), 1);
       trust = HTTP_TRUST_INVALID;
     }
   }
+  else if ((!cg->any_root || require_ca) && sk_X509_num(certs) == 1)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1);
+    trust = HTTP_TRUST_INVALID;
+  }
 
   if (trust == HTTP_TRUST_OK && !cg->expired_certs)
   {
@@ -869,12 +904,6 @@ cupsGetCredentialsTrust(
     }
   }
 
-  if (trust == HTTP_TRUST_OK && !cg->any_root && sk_X509_num(certs) == 1)
-  {
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Self-signed credentials are blocked."), 1);
-    trust = HTTP_TRUST_INVALID;
-  }
-
   sk_X509_free(certs);
 
   return (trust);
@@ -1320,14 +1349,14 @@ httpCopyPeerCredentials(http_t *http)   // I - Connection to server
   STACK_OF(X509) *chain;               // Certificate chain
 
 
-  DEBUG_printf("httpCopyCredentials(http=%p)", (void *)http);
+  DEBUG_printf("httpCopyPeerCredentials(http=%p)", (void *)http);
 
   if (http && http->tls)
   {
     // Get the chain of certificates for the remote end...
     chain = SSL_get_peer_cert_chain(http->tls);
 
-    DEBUG_printf("1httpCopyCredentials: chain=%p", (void *)chain);
+    DEBUG_printf("1httpCopyPeerCredentials: chain=%p", (void *)chain);
 
     if (chain)
     {
@@ -1342,6 +1371,21 @@ httpCopyPeerCredentials(http_t *http)    // I - Connection to server
        BIO     *bio = BIO_new(BIO_s_mem());
                                          // Memory buffer for cert
 
+        DEBUG_printf("1httpCopyPeerCredentials: chain[%d/%d]=%p", i + 1, count, cert);
+
+#ifdef DEBUG
+       char subjectName[256], issuerName[256];
+       X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, subjectName, sizeof(subjectName));
+       X509_NAME_get_text_by_NID(X509_get_issuer_name(cert), NID_commonName, issuerName, sizeof(issuerName));
+       DEBUG_printf("1httpCopyPeerCredentials: subjectName=\"%s\", issuerName=\"%s\"", subjectName, issuerName);
+
+       STACK_OF(GENERAL_NAME) *names;  // subjectAltName values
+       names = X509_get_ext_d2i(cert, NID_subject_alt_name, /*crit*/NULL, /*idx*/NULL);
+       DEBUG_printf("1httpCopyPeerCredentials: subjectAltNames=%p(%d)", names, names ? sk_GENERAL_NAME_num(names) : 0);
+        if (names)
+          GENERAL_NAMES_free(names);
+#endif // DEBUG
+
        if (bio)
        {
          long  bytes;                  // Number of bytes
@@ -1371,6 +1415,8 @@ httpCopyPeerCredentials(http_t *http)     // I - Connection to server
     }
   }
 
+  DEBUG_printf("1httpCopyPeerCredentials: Returning \"%s\".", credentials);
+
   return (credentials);
 }
 
@@ -2331,6 +2377,8 @@ openssl_load_x509(
       X509_free(cert);
       break;
     }
+
+    cert = NULL;
   }
 
   BIO_free(bio);
index 174c0bc8d4740648b35551cd742e64d9ed5b9d04..c02b73570e604c32f8ce68922a8afd759708b9e3 100644 (file)
 //
 
 #include "cups-private.h"
+#include "dir.h"
 #include <fcntl.h>
 #include <math.h>
 #include <sys/stat.h>
+#ifdef __APPLE__
+#  include <Security/Security.h>
+#endif // __APPLE__
 #ifdef _WIN32
 #  include <tchar.h>
 #else
@@ -38,15 +42,23 @@ static cups_mutex_t tls_mutex = CUPS_MUTEX_INITIALIZER;
 static int             tls_options = -1,// Options for TLS connections
                        tls_min_version = _HTTP_TLS_1_2,
                        tls_max_version = _HTTP_TLS_MAX;
+#ifndef __APPLE__
+static cups_array_t    *tls_root_certs = NULL;
+                                       // List of known root CAs
+#endif // __APPLE__
 
 
 //
 // Local functions...
 //
 
+static bool            http_check_roots(const char *creds);
 static char            *http_copy_file(const char *path, const char *common_name, const char *ext);
 static const char      *http_default_path(char *buffer, size_t bufsize);
 static bool            http_default_san_cb(const char *common_name, const char *subject_alt_name, void *data);
+#ifdef _WIN32
+static char            *http_der_to_pem(const unsigned char *der, size_t dersize);
+#endif // _WIN32
 static const char      *http_make_path(char *buffer, size_t bufsize, const char *dirname, const char *filename, const char *ext);
 static bool            http_save_file(const char *path, const char *common_name, const char *ext, const char *value);
 
@@ -113,7 +125,7 @@ bool                                        // O - `true` on success, `false` on failure
 cupsSaveCredentials(
     const char *path,                  // I - Directory path for certificate/key store or `NULL` for default
     const char *common_name,           // I - Common name for certificate
-    const char *credentials,           // I - PEM-encoded certificate chain
+    const char *credentials,           // I - PEM-encoded certificate chain or `NULL` to remove
     const char *key)                   // I - PEM-encoded private key or `NULL` for none
 {
   if (http_save_file(path, common_name, "crt", credentials))
@@ -195,6 +207,200 @@ _httpTLSSetOptions(int options,           // I - Options
 }
 
 
+//
+// 'http_check_roots()' - Check whether the supplied credentials use a trusted root CA.
+//
+
+static bool                            // O - `true` if they use a trusted root, `false` otherwise
+http_check_roots(const char *creds)    // I - Credentials
+{
+  bool         ret = false;            // Return value
+
+
+#ifdef __APPLE__
+  // Apple hides all of the keychain stuff (all deprecated) so the best we can
+  // do is use the SecTrust API to evaluate the certificate...
+  CFMutableArrayRef    certs = NULL;   // Certificates from credentials
+  SecCertificateRef    cert;
+  char                 *tcreds = NULL, // Copy of credentials string
+                       *tstart,        // Start of certificate data
+                       *tend,          // End of certificate data
+                       *der = NULL;    // DER-encoded fragment buffer
+  size_t               dersize,        // Size of DER buffer
+                       derlen;         // Length of DER data
+  SecPolicyRef         policy;         // X.509 policy
+  SecTrustRef          trust;          // Trust evaluator
+
+
+  // Convert PEM-encoded credentials to an array of DER-encoded certificates...
+  if ((tcreds = strdup(creds)) == NULL)
+    goto done;
+
+  if ((certs = CFArrayCreateMutable(kCFAllocatorDefault, /*capacity*/0, &kCFTypeArrayCallBacks)) == NULL)
+    goto done;
+
+  dersize = 3 * strlen(tcreds) / 4;
+  if ((der = malloc(dersize)) == NULL)
+    goto done;
+
+  for (tstart = strstr(tcreds, "-----BEGIN CERTIFICATE-----\n"); tstart; tstart = strstr(tend, "-----BEGIN CERTIFICATE-----\n"))
+  {
+    // Find the end of the certificate data...
+    tstart += 28;                      // Skip "-----BEGIN CERTIFICATE-----\n"
+    if ((tend = strstr(tstart, "-----END CERTIFICATE-----\n")) == NULL)
+      break;                           // Missing end...
+
+    // Nul-terminate the cert data...
+    *tend++ = '\0';
+
+    // Convert to DER format
+    derlen = dersize;
+    if (httpDecode64_3(der, &derlen, tstart, /*end*/NULL))
+    {
+      // Create a CFData object for the data...
+      CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)der, (CFIndex)derlen);
+
+      if (data)
+      {
+        // Create a certificate from the DER data...
+        if ((cert = SecCertificateCreateWithData(kCFAllocatorDefault, data)) != NULL)
+        {
+          // Add certificate to the array...
+          CFArrayAppendValue(certs, cert);
+          CFRelease(cert);
+       }
+
+        CFRelease(data);
+      }
+    }
+  }
+
+  // Test the certificate list against the macOS/iOS trust store...
+  if ((policy = SecPolicyCreateBasicX509()) != NULL)
+  {
+    if (SecTrustCreateWithCertificates(certs, policy, &trust) == noErr)
+    {
+      ret = SecTrustEvaluateWithError(trust, NULL);
+      CFRelease(trust);
+    }
+
+    CFRelease(policy);
+  }
+
+  done:
+
+  free(tcreds);
+  free(der);
+
+  if (certs)
+    CFRelease(certs);
+
+#else
+  size_t       credslen;               // Length of credentials string
+  const char   *rcreds;                // Current root credential
+  size_t       rcredslen;              // Length of current root credential
+
+
+  cupsMutexLock(&tls_mutex);
+
+  // Load root certificates as needed...
+  if (!tls_root_certs)
+  {
+    // Load root certificates...
+    tls_root_certs = cupsArrayNew(/*cb*/NULL, /*cb_data*/NULL, /*hash_cb*/NULL, /*hash_size*/0, /*copy_cb*/NULL, /*free_cb*/NULL);
+
+#  ifdef _WIN32
+    int                        i;              // Looping var
+    HCERTSTORE         store;          // Certificate store
+    CERT_CONTEXT       *cert;          // Current certificate
+
+    // Add certificates in both the "ROOT" and "CA" stores...
+    for (i = 0; i < 2; i ++)
+    {
+      if ((store = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, i ? L"CA" : L"ROOT")) == NULL)
+        continue;
+
+      // Loop through certificates...
+      for (cert = CertEnumCertificatesInStore(store, NULL); cert; cert = CertEnumCertificatesInStore(store, cert))
+      {
+        if (cert->dwCertEncodingType == X509_ASN_ENCODING)
+        {
+          // Convert DER to PEM and add to the list...
+          char * pem = http_der_to_pem(cert->pbCertEncoded, cert->cbCertEncoded);
+
+          if (pem)
+            cupsArrayAdd(tls_root_certs, pem);
+       }
+      }
+
+      CertCloseStore(store, 0);
+    }
+
+#  else
+    size_t             i;              // Looping var
+    cups_dir_t         *dir;           // Directory
+    cups_dentry_t      *dent;          // Directory entry
+    const char         *ext;           // Pointer to filename extension
+    static const char * const root_dirs[] =
+    {                                  // Root certificate stores
+      "/etc/ssl/certs",
+      "/system/etc/security/cacerts/",
+
+    };
+
+    for (i = 0, dir = NULL; i < (sizeof(root_dirs) / sizeof(root_dirs[0])); i ++)
+    {
+      if ((dir = cupsDirOpen(root_dirs[i])) != NULL)
+        break;
+    }
+
+    if (dir)
+    {
+      while ((dent = cupsDirRead(dir)) != NULL)
+      {
+        if ((ext = strrchr(dent->filename, '.')) != NULL && !strcmp(ext, ".pem"))
+        {
+          char filename[1024],         // Certificate filename
+               *cert;                  // Certificate data
+         int   fd;                     // File descriptor
+
+         snprintf(filename, sizeof(filename), "%s/%s", root_dirs[i], dent->filename);
+          if ((fd = open(filename, O_RDONLY)) >= 0)
+          {
+            if ((cert = calloc(1, (size_t)(dent->fileinfo.st_size + 1))) != NULL)
+           {
+             read(fd, cert, (size_t)dent->fileinfo.st_size);
+             cupsArrayAdd(tls_root_certs, cert);
+           }
+
+           close(fd);
+         }
+       }
+      }
+    }
+#  endif // _WIN32
+  }
+
+  // Check all roots
+  credslen = strlen(creds);
+
+  for (rcreds = (const char *)cupsArrayGetFirst(tls_root_certs); rcreds && !ret; rcreds = (const char *)cupsArrayGetNext(tls_root_certs))
+  {
+    // Compare the root against the tail of the current credentials...
+    rcredslen = strlen(rcreds);
+
+    if (credslen >= rcredslen && !strcmp(creds + (credslen - rcredslen), rcreds))
+      ret = true;
+  }
+
+  // Unlock access and return...
+  cupsMutexUnlock(&tls_mutex);
+#endif // __APPLE__
+
+  return (ret);
+}
+
+
 //
 // 'http_copy_file()' - Copy the contents of a file to a string.
 //
@@ -280,13 +486,13 @@ http_default_path(
   }
   else
   {
-    if (mkdir(cg->cups_serverroot, 0755) && errno != EEXIST)
+    if (mkdir(cg->sysconfig, 0755) && errno != EEXIST)
     {
-      DEBUG_printf("1http_default_path: Failed to make directory '%s': %s", cg->cups_serverroot, strerror(errno));
+      DEBUG_printf("1http_default_path: Failed to make directory '%s': %s", cg->sysconfig, strerror(errno));
       return (NULL);
     }
 
-    snprintf(buffer, bufsize, "%s/ssl", cg->cups_serverroot);
+    snprintf(buffer, bufsize, "%s/ssl", cg->sysconfig);
 
     if (mkdir(buffer, 0700) && errno != EEXIST)
     {
@@ -325,6 +531,81 @@ http_default_san_cb(
 }
 
 
+#ifdef _WIN32
+//
+// 'http_der_to_pem()' - Convert DER format certificate data to PEM.
+//
+
+static char *                          // O - PEM string
+http_der_to_pem(
+     const unsigned char *der,         // I - DER-encoded data
+     size_t              dersize)      // I - Size of DER-encoded data
+{
+  char         *pem,                   // PEM-encoded string
+               *pemptr;                // Pointer into PEM-encoded string
+  int          col;                    // Current column
+  size_t       pemsize;                // Size of PEM-encoded string
+  static const char *base64 =          // Base64 alphabet
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+
+  // Calculate the size, accounting for Base64 expansion, line wrapping at
+  // column 64, and the BEGIN/END CERTIFICATE text...
+  pemsize = 65 * 4 * dersize / 3 / 64 + /*"-----BEGIN CERTIFICATE-----"*/28 + /*"-----END CERTIFICATE-----"*/26 + 2;
+
+  if ((pem = calloc(1, pemsize)) == NULL)
+    return (NULL);
+
+  cupsCopyString(pem, "-----BEGIN CERTIFICATE-----\n", pemsize);
+  for (pemptr = pem, col = 0; dersize > 0; der += 3)
+  {
+    // Encode the up to 3 characters as 4 Base64 numbers...
+    switch (dersize)
+    {
+      case 1 :
+          *pemptr ++ = base64[(der[0] & 255) >> 2];
+         *pemptr ++ = base64[((der[0] & 255) << 4) & 63];
+         *pemptr ++ = '=';
+         *pemptr ++ = '=';
+         dersize = 0;
+          break;
+      case 2 :
+          *pemptr ++ = base64[(der[0] & 255) >> 2];
+         *pemptr ++ = base64[(((der[0] & 255) << 4) | ((der[1] & 255) >> 4)) & 63];
+         *pemptr ++ = base64[((der[1] & 255) << 2) & 63];
+         *pemptr ++ = '=';
+         dersize = 0;
+          break;
+      default :
+          *pemptr ++ = base64[(der[0] & 255) >> 2];
+         *pemptr ++ = base64[(((der[0] & 255) << 4) | ((der[1] & 255) >> 4)) & 63];
+         *pemptr ++ = base64[(((der[1] & 255) << 2) | ((der[2] & 255) >> 6)) & 63];
+         *pemptr ++ = base64[der[2] & 63];
+         dersize -= 3;
+          break;
+    }
+
+    // Add a newline as needed...
+    col += 4;
+    if (col >= 64)
+    {
+      *pemptr++ = '\n';
+      col = 0;
+    }
+  }
+
+  if (col > 0)
+    *pemptr++ = '\n';
+  *pemptr = '\0';
+
+  cupsConcatString(pem, "-----END CERTIFICATE-----\n", pemsize);
+
+  // Return the encoded string...
+  return (pem);
+}
+#endif // _WIN32
+
+
 //
 // 'http_make_path()' - Format a filename for a certificate or key file.
 //
@@ -379,14 +660,22 @@ http_save_file(const char *path,  // I - Directory path for certificate/key store
 
 
   // Range check input...
-  if (!common_name || !value)
+  if (!common_name)
     return (false);
 
   // Get default path as needed...
   if (!path)
     path = http_default_path(defpath, sizeof(defpath));
 
-  if ((fd = open(http_make_path(filename, sizeof(filename), path, common_name, ext), O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
+  http_make_path(filename, sizeof(filename), path, common_name, ext);
+
+  if (!value)
+  {
+    unlink(filename);
+    return (true);
+  }
+
+  if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
     return (false);
 
   if (write(fd, value, strlen(value)) < 0)
index 29d5ad57b3f2c0255cd7c28422cbc9b25b1cc1e8..4c6e077572eb98c7fc7d80c7383b9d92ae4e1189 100644 (file)
@@ -1094,24 +1094,20 @@ _cupsSetDefaults(void)
   * present.
   */
 
-  snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
+  snprintf(filename, sizeof(filename), "%s/client.conf", cg->sysconfig);
   if ((fp = cupsFileOpen(filename, "r")) != NULL)
   {
     cups_read_client_conf(fp, &cc);
     cupsFileClose(fp);
   }
 
-  if (cg->home)
+  if (cg->userconfig)
   {
    /*
     * Look for ~/.cups/client.conf...
     */
 
-#if _WIN32
-    snprintf(filename, sizeof(filename), "%s/AppData/Local/cups/client.conf", cg->home);
-#else
-    snprintf(filename, sizeof(filename), "%s/.cups/client.conf", cg->home);
-#endif // _WIN32
+    snprintf(filename, sizeof(filename), "%s/client.conf", cg->userconfig);
 
     if ((fp = cupsFileOpen(filename, "r")) != NULL)
     {
index f304328e536caa9562abc5e7b19160e6e72145d3..d2297109ffc2b0dab72b031f81c57bb70e70b1b2 100644 (file)
@@ -1877,7 +1877,7 @@ show_printers(const char  *printers,      /* I - Destinations */
            if (make_model && !strstr(make_model, "Raw Printer"))
              _cupsLangPrintf(stdout,
                              _("\tInterface: %s/ppd/%s.ppd"),
-                             cg->cups_serverroot, printer);
+                             cg->sysconfig, printer);
           }
          _cupsLangPuts(stdout, _("\tOn fault: no alert"));
          _cupsLangPuts(stdout, _("\tAfter fault: continue"));
@@ -1996,7 +1996,7 @@ show_printers(const char  *printers,      /* I - Destinations */
                if (make_model && !strstr(make_model, "Raw Printer"))
                  _cupsLangPrintf(stdout,
                                  _("\tInterface: %s/ppd/%s.ppd"),
-                                 cg->cups_serverroot, printer);
+                                 cg->sysconfig, printer);
               }
              _cupsLangPuts(stdout, _("\tOn fault: no alert"));
              _cupsLangPuts(stdout, _("\tAfter fault: continue"));