]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/dest.c
Sandboxed applications were not able to get the default printer (Issue #5676)
[thirdparty/cups.git] / cups / dest.c
index b7a1db7ec1648538393351ad3f909868466f0d54..fd57d979461646440a818ee624c0feeb11e2bbd6 100644 (file)
@@ -1,10 +1,11 @@
 /*
  * User-defined destination (and option) support for CUPS.
  *
- * Copyright 2007-2018 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products.
+ * Copyright © 2007-2019 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products.
  *
- * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
@@ -12,6 +13,7 @@
  */
 
 #include "cups-private.h"
+#include "debug-internal.h"
 #include <sys/stat.h>
 
 #ifdef HAVE_NOTIFY_H
  */
 
 #ifdef __APPLE__
-#  if !TARGET_OS_IOS
+#  if HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME
 #    include <SystemConfiguration/SystemConfiguration.h>
 #    define _CUPS_LOCATION_DEFAULTS 1
-#  endif /* !TARGET_OS_IOS */
+#  endif /* HAVE_SCDYNAMICSTORECOPYCOMPUTERNAME */
 #  define kCUPSPrintingPrefs   CFSTR("org.cups.PrintingPrefs")
 #  define kDefaultPaperIDKey   CFSTR("DefaultPaperID")
 #  define kLastUsedPrintersKey CFSTR("LastUsedPrinters")
@@ -563,7 +565,7 @@ _cupsAppleSetUseLastPrinter(
 
 
 /*
- * 'cupsConnectDest()' - Open a conection to the destination.
+ * 'cupsConnectDest()' - Open a connection to the destination.
  *
  * Connect to the destination, returning a new @code http_t@ connection object
  * and optionally the resource path to use for the destination.  These calls
@@ -572,7 +574,7 @@ _cupsAppleSetUseLastPrinter(
  * returns 0.  The caller is responsible for calling @link httpClose@ on the
  * returned connection.
  *
- * Starting with CUPS 2.2.4, the caller can pass  @code CUPS_DEST_FLAGS_DEVICE@
+ * Starting with CUPS 2.2.4, the caller can pass @code CUPS_DEST_FLAGS_DEVICE@
  * for the "flags" argument to connect directly to the device associated with
  * the destination.  Otherwise, the connection is made to the CUPS scheduler
  * associated with the destination.
@@ -840,6 +842,8 @@ cupsCopyDest(cups_dest_t *dest,         /* I  - Destination to copy */
 
   if (new_dest)
   {
+    new_dest->is_default = dest->is_default;
+
     if ((new_dest->options = calloc(sizeof(cups_option_t), (size_t)dest->num_options)) == NULL)
       return (cupsRemoveDest(dest->name, dest->instance, num_dests, dests));
 
@@ -1092,20 +1096,23 @@ cupsGetDest(const char  *name,          /* I - Destination name or @code NULL@ for the d
  * '_cupsGetDestResource()' - Get the resource path and URI for a destination.
  */
 
-const char *                           /* O - Printer URI */
+const char *                           /* O - URI */
 _cupsGetDestResource(
     cups_dest_t *dest,                 /* I - Destination */
+    unsigned    flags,                 /* I - Destination flags */
     char        *resource,             /* I - Resource buffer */
     size_t      resourcesize)          /* I - Size of resource buffer */
 {
-  const char   *uri;                   /* Printer URI */
+  const char   *uri,                   /* URI */
+               *device_uri,            /* Device URI */
+               *printer_uri;           /* Printer URI */
   char         scheme[32],             /* URI scheme */
                userpass[256],          /* Username and password (unused) */
                hostname[256];          /* Hostname */
   int          port;                   /* Port number */
 
 
-  DEBUG_printf(("_cupsGetDestResource(dest=%p(%s), resource=%p, resourcesize=%d)", (void *)dest, dest->name, (void *)resource, (int)resourcesize));
+  DEBUG_printf(("_cupsGetDestResource(dest=%p(%s), flags=%u, resource=%p, resourcesize=%d)", (void *)dest, dest->name, flags, (void *)resource, (int)resourcesize));
 
  /*
   * Range check input...
@@ -1121,25 +1128,46 @@ _cupsGetDestResource(
   }
 
  /*
-  * Grab the printer URI...
+  * Grab the printer and device URIs...
   */
 
-  if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
+  device_uri  = cupsGetOption("device-uri", dest->num_options, dest->options);
+  printer_uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
+
+  DEBUG_printf(("1_cupsGetDestResource: device-uri=\"%s\", printer-uri-supported=\"%s\".", device_uri, printer_uri));
+
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+  if (((flags & CUPS_DEST_FLAGS_DEVICE) || !printer_uri) && strstr(device_uri, "._tcp"))
   {
-    if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
+    if ((device_uri = cups_dnssd_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL)
     {
-#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
-      if (strstr(uri, "._tcp"))
-        uri = cups_dnssd_resolve(dest, uri, 5000, NULL, NULL, NULL);
-#endif /* HAVE_DNSSD || HAVE_AVAHI */
+      DEBUG_printf(("1_cupsGetDestResource: Resolved device-uri=\"%s\".", device_uri));
     }
-
-    if (uri)
+    else
     {
-      DEBUG_printf(("1_cupsGetDestResource: Resolved printer-uri-supported=\"%s\"", uri));
+      DEBUG_puts("1_cupsGetDestResource: Unable to resolve device.");
 
-      uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, uri, resource, resourcesize);
+      if (resource)
+       *resource = '\0';
+
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+
+      return (NULL);
     }
+  }
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+
+  if (flags & CUPS_DEST_FLAGS_DEVICE)
+  {
+    uri = device_uri;
+  }
+  else if (printer_uri)
+  {
+    uri = printer_uri;
+  }
+  else
+  {
+    uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, device_uri, resource, resourcesize);
 
     if (uri)
     {
@@ -1149,30 +1177,24 @@ _cupsGetDestResource(
 
       uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
     }
-    else
-    {
-      DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported found.");
+  }
 
-      if (resource)
-        *resource = '\0';
+  if (!uri)
+  {
+    DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported or device-uri found.");
 
-      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+    if (resource)
+      *resource = '\0';
 
-      return (NULL);
-    }
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+
+    return (NULL);
   }
-  else
+  else if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
   {
-    DEBUG_printf(("1_cupsGetDestResource: printer-uri-supported=\"%s\"", uri));
-
-    if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
-                        userpass, sizeof(userpass), hostname, sizeof(hostname),
-                        &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
-    {
-      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1);
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad URI."), 1);
 
-      return (NULL);
-    }
+    return (NULL);
   }
 
   DEBUG_printf(("1_cupsGetDestResource: resource=\"%s\"", resource));
@@ -1260,6 +1282,12 @@ cupsGetDestWithURI(const char *name,     /* I - Desired printer name or @code NULL@
       name = resource + 10;
       info = temp;
     }
+    else if (!strncmp(resource, "/ipp/print/", 11))
+    {
+      snprintf(temp, sizeof(temp), "%s @ %s", resource + 11, hostname);
+      name = resource + 11;
+      info = temp;
+    }
     else
     {
       name = hostname;
@@ -1720,7 +1748,6 @@ cupsGetNamedDest(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
   cups_dest_t  *dest;                  /* Destination */
   char         filename[1024],         /* Path to lpoptions */
                defname[256];           /* Default printer name */
-  const char   *home = getenv("HOME"); /* Home directory */
   int          set_as_default = 0;     /* Set returned destination as default */
   ipp_op_t     op = IPP_OP_GET_PRINTER_ATTRIBUTES;
                                        /* IPP operation to get server ops */
@@ -1752,13 +1779,13 @@ cupsGetNamedDest(http_t     *http,      /* I - Connection to server or @code CUPS_HTT
       else
         instance = NULL;
     }
-    else if (home)
+    else if (cg->home)
     {
      /*
       * No default in the environment, try the user's lpoptions files...
       */
 
-      snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+      snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
 
       dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
 
@@ -1864,9 +1891,9 @@ cupsGetNamedDest(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
   snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
   cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest);
 
-  if (home)
+  if (cg->home)
   {
-    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
 
     cups_get_dests(filename, dest_name, instance, 0, 1, 1, &dest);
   }
@@ -2004,9 +2031,6 @@ cupsSetDests2(http_t      *http,  /* I - Connection to server or @code CUPS_HTTP_
   cups_option_t        *option;                /* Current option */
   _ipp_option_t        *match;                 /* Matching attribute for option */
   FILE         *fp;                    /* File pointer */
-#ifndef WIN32
-  const char   *home;                  /* HOME environment variable */
-#endif /* WIN32 */
   char         filename[1024];         /* lpoptions file */
   int          num_temps;              /* Number of temporary destinations */
   cups_dest_t  *temps = NULL,          /* Temporary destinations */
@@ -2040,27 +2064,18 @@ cupsSetDests2(http_t      *http,        /* I - Connection to server or @code CUPS_HTTP_
 
   snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
 
-#ifndef WIN32
-  if (getuid())
+  if (cg->home)
   {
    /*
-    * Point to user defaults...
+    * Create ~/.cups subdirectory...
     */
 
-    if ((home = getenv("HOME")) != NULL)
-    {
-     /*
-      * Create ~/.cups subdirectory...
-      */
+    snprintf(filename, sizeof(filename), "%s/.cups", cg->home);
+    if (access(filename, 0))
+      mkdir(filename, 0700);
 
-      snprintf(filename, sizeof(filename), "%s/.cups", home);
-      if (access(filename, 0))
-        mkdir(filename, 0700);
-
-      snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
-    }
+    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
   }
-#endif /* !WIN32 */
 
  /*
   * Try to open the file...
@@ -2072,7 +2087,7 @@ cupsSetDests2(http_t      *http,  /* I - Connection to server or @code CUPS_HTTP_
     return (-1);
   }
 
-#ifndef WIN32
+#ifndef _WIN32
  /*
   * Set the permissions to 0644 when saving to the /etc/cups/lpoptions
   * file...
@@ -2080,7 +2095,7 @@ cupsSetDests2(http_t      *http,  /* I - Connection to server or @code CUPS_HTTP_
 
   if (!getuid())
     fchmod(fileno(fp), 0644);
-#endif /* !WIN32 */
+#endif /* !_WIN32 */
 
  /*
   * Write each printer; each line looks like:
@@ -2887,9 +2902,9 @@ cups_dnssd_poll_cb(
  * 'cups_dnssd_query_cb()' - Process query data.
  */
 
-#  ifdef HAVE_DNSSD
 static void
 cups_dnssd_query_cb(
+#  ifdef HAVE_DNSSD
     DNSServiceRef       sdRef,         /* I - Service reference */
     DNSServiceFlags     flags,         /* I - Data flags */
     uint32_t            interfaceIndex,        /* I - Interface */
@@ -2900,11 +2915,7 @@ cups_dnssd_query_cb(
     uint16_t            rdlen,         /* I - Length of record data */
     const void          *rdata,                /* I - Record data */
     uint32_t            ttl,           /* I - Time-to-live */
-    void                *context)      /* I - Enumeration data */
-{
 #  else /* HAVE_AVAHI */
-static void
-cups_dnssd_query_cb(
     AvahiRecordBrowser     *browser,   /* I - Record browser */
     AvahiIfIndex           interfaceIndex,
                                        /* I - Interface index (unused) */
@@ -2916,13 +2927,13 @@ cups_dnssd_query_cb(
     const void             *rdata,     /* I - TXT record */
     size_t                 rdlen,      /* I - Length of TXT record */
     AvahiLookupResultFlags flags,      /* I - Flags */
+#  endif /* HAVE_DNSSD */
     void                *context)      /* I - Enumeration data */
 {
-#    ifdef DEBUG
+#  if defined(DEBUG) && defined(HAVE_AVAHI)
   AvahiClient          *client = avahi_record_browser_get_client(browser);
                                        /* Client information */
-#    endif /* DEBUG */
-#  endif /* HAVE_DNSSD */
+#  endif /* DEBUG && HAVE_AVAHI */
   _cups_dnssd_data_t   *data = (_cups_dnssd_data_t *)context;
                                        /* Enumeration data */
   char                 serviceName[256],/* Service name */
@@ -3402,7 +3413,6 @@ cups_enum_dests(
 #else
   _cups_getdata_t data;                        /* Data for callback */
 #endif /* HAVE_DNSSD || HAVE_AVAHI */
-  const char   *home;                  /* HOME environment variable */
   char         filename[1024];         /* Local lpoptions file */
   _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
 
@@ -3446,16 +3456,28 @@ cups_enum_dests(
       *data.def_instance++ = '\0';
   }
 
+  DEBUG_printf(("1cups_enum_dests: def_name=\"%s\", def_instance=\"%s\"", data.def_name, data.def_instance));
+
   snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
   data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests);
 
-  if ((home = getenv("HOME")) != NULL)
+  if (cg->home)
   {
-    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
+    snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", cg->home);
 
     data.num_dests = cups_get_dests(filename, NULL, NULL, 1, user_default != NULL, data.num_dests, &data.dests);
   }
 
+  if (!data.def_name[0] && (user_dest = cupsGetDest(NULL, NULL, data.num_dests, data.dests)) != NULL)
+  {
+   /*
+    * Use an lpoptions default printer...
+    */
+
+    strlcpy(data.def_name, user_dest->name, sizeof(data.def_name));
+    data.def_instance = user_dest->instance;
+  }
+
  /*
   * Get ready to enumerate...
   */
@@ -3483,7 +3505,10 @@ cups_enum_dests(
       */
 
       if ((dest = cupsGetDest(data.def_name, data.def_instance, num_dests, dests)) != NULL)
+      {
+       DEBUG_printf(("1cups_enum_dests: Setting is_default on \"%s/%s\".", dest->name, dest->instance));
         dest->is_default = 1;
+      }
     }
 
     for (i = num_dests, dest = dests;
@@ -3773,7 +3798,10 @@ cups_enum_dests(
          }
 
           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))