]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/process.c
Fix lpadmin error reporting for IPP Everywhere printers (Issue #5370)
[thirdparty/cups.git] / scheduler / process.c
index 97da1eaa231987e65d0f10e8f67b6faba63e54fc..3c1c6ba4f9d49fcc3ebb82dd5e446f902ad2e636 100644 (file)
@@ -1,16 +1,10 @@
 /*
- * "$Id$"
- *
  * Process management routines for the CUPS scheduler.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file.  If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more information.
  */
 
 /*
 #ifdef HAVE_POSIX_SPAWN
 #  include <spawn.h>
 extern char **environ;
+/* Don't use posix_spawn on systems with bugs in their implementations... */
+#  if defined(OpenBSD) && OpenBSD < 201505
+#    define USE_POSIX_SPAWN 0
+#  elif defined(__UCLIBC__) && __UCLIBC_MAJOR__ == 1 && __UCLIBC_MINOR__ == 0 && __UCLIBC_SUBLEVEL__ < 27
+#    define USE_POSIX_SPAWN 0
+#  elif defined(__UCLIBC__) && __UCLIBC_MAJOR__ < 1
+#    define USE_POSIX_SPAWN 0
+#  else /* All other platforms */
+#    define USE_POSIX_SPAWN 1
+#  endif /* ... */
+#else
+#  define USE_POSIX_SPAWN 0
 #endif /* HAVE_POSIX_SPAWN */
 
 
@@ -62,58 +68,73 @@ static char *cupsd_requote(char *dst, const char *src, size_t dstsize);
  */
 
 void *                                 /* O - Profile or NULL on error */
-cupsdCreateProfile(int job_id)         /* I - Job ID or 0 for none */
+cupsdCreateProfile(int job_id,         /* I - Job ID or 0 for none */
+                   int allow_networking)/* I - Allow networking off machine? */
 {
 #ifdef HAVE_SANDBOX_H
-  cups_file_t  *fp;                    /* File pointer */
-  char         profile[1024],          /* File containing the profile */
-               cache[1024],            /* Quoted CacheDir */
-               request[1024],          /* Quoted RequestRoot */
-               root[1024],             /* Quoted ServerRoot */
-               temp[1024];             /* Quoted TempDir */
-  const char   *nodebug;               /* " (with no-log)" for no debug */
-
-
-  if (!UseProfiles)
+  cups_file_t          *fp;            /* File pointer */
+  char                 profile[1024],  /* File containing the profile */
+                       bin[1024],      /* Quoted ServerBin */
+                       cache[1024],    /* Quoted CacheDir */
+                       domain[1024],   /* Domain socket, if any */
+                       request[1024],  /* Quoted RequestRoot */
+                       root[1024],     /* Quoted ServerRoot */
+                       state[1024],    /* Quoted StateDir */
+                       temp[1024];     /* Quoted TempDir */
+  const char           *nodebug;       /* " (with no-log)" for no debug */
+  cupsd_listener_t     *lis;           /* Current listening socket */
+
+
+  if (!UseSandboxing || Sandboxing == CUPSD_SANDBOXING_OFF)
   {
    /*
     * Only use sandbox profiles as root...
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
-                    job_id);
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking);
 
     return (NULL);
   }
 
   if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL)
   {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
-                    job_id);
-    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s",
-                    strerror(errno));
+   /*
+    * This should never happen, and is fatal when sandboxing is enabled.
+    */
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking);
+    cupsdLogMessage(CUPSD_LOG_EMERG, "Unable to create security profile: %s", strerror(errno));
+    kill(getpid(), SIGTERM);
     return (NULL);
   }
 
   fchown(cupsFileNumber(fp), RunUser, Group);
   fchmod(cupsFileNumber(fp), 0640);
 
+  cupsd_requote(bin, ServerBin, sizeof(bin));
   cupsd_requote(cache, CacheDir, sizeof(cache));
   cupsd_requote(request, RequestRoot, sizeof(request));
   cupsd_requote(root, ServerRoot, sizeof(root));
+  cupsd_requote(state, StateDir, sizeof(state));
   cupsd_requote(temp, TempDir, sizeof(temp));
 
   nodebug = LogLevel < CUPSD_LOG_DEBUG ? " (with no-log)" : "";
 
   cupsFilePuts(fp, "(version 1)\n");
-  cupsFilePuts(fp, "(allow default)\n");
-  cupsFilePrintf(fp,
-                 "(deny file-write* file-read-data file-read-metadata\n"
-                 "  (regex"
-                " #\"^%s$\""           /* RequestRoot */
-                " #\"^%s/\""           /* RequestRoot/... */
-                ")%s)\n",
-                request, request, nodebug);
+  if (Sandboxing == CUPSD_SANDBOXING_STRICT)
+    cupsFilePuts(fp, "(deny default)\n");
+  else
+    cupsFilePuts(fp, "(allow default)\n");
+  if (LogLevel >= CUPSD_LOG_DEBUG)
+    cupsFilePuts(fp, "(debug deny)\n");
+  cupsFilePuts(fp, "(import \"system.sb\")\n");
+  cupsFilePuts(fp, "(import \"com.apple.corefoundation.sb\")\n");
+  cupsFilePuts(fp, "(system-network)\n");
+  cupsFilePuts(fp, "(allow mach-per-user-lookup)\n");
+  cupsFilePuts(fp, "(allow ipc-posix-sem)\n");
+  cupsFilePuts(fp, "(allow ipc-posix-shm)\n");
+  cupsFilePuts(fp, "(allow ipc-sysv-shm)\n");
+  cupsFilePuts(fp, "(allow mach-lookup)\n");
   if (!RunUser)
     cupsFilePrintf(fp,
                   "(deny file-write* file-read-data file-read-metadata\n"
@@ -136,13 +157,43 @@ cupsdCreateProfile(int job_id)            /* I - Job ID or 0 for none */
                 " #\"^/System/\""
                 ")%s)\n",
                 root, root, nodebug);
-  /* Specifically allow applications to stat RequestRoot */
+  /* Specifically allow applications to stat RequestRoot and some other system folders */
   cupsFilePrintf(fp,
                  "(allow file-read-metadata\n"
                  "  (regex"
+                " #\"^/$\""            /* / */
+                " #\"^/usr$\""         /* /usr */
+                " #\"^/Library$\""     /* /Library */
+                " #\"^/Library/Printers$\""    /* /Library/Printers */
                 " #\"^%s$\""           /* RequestRoot */
                 "))\n",
                 request);
+  /* Read and write TempDir, CacheDir, and other common folders */
+  cupsFilePuts(fp,
+              "(allow file-write* file-read-data file-read-metadata\n"
+              "  (regex"
+              " #\"^/private/var/db/\""
+              " #\"^/private/var/folders/\""
+              " #\"^/private/var/lib/\""
+              " #\"^/private/var/log/\""
+              " #\"^/private/var/mysql/\""
+              " #\"^/private/var/run/\""
+              " #\"^/private/var/spool/\""
+              " #\"^/Library/Application Support/\""
+              " #\"^/Library/Caches/\""
+              " #\"^/Library/Logs/\""
+              " #\"^/Library/Preferences/\""
+              " #\"^/Library/WebServer/\""
+              " #\"^/Users/Shared/\""
+              "))\n");
+  cupsFilePrintf(fp,
+                "(deny file-write*\n"
+                "       (regex #\"^%s$\")%s)\n",
+                request, nodebug);
+  cupsFilePrintf(fp,
+                "(deny file-write* file-read-data file-read-metadata\n"
+                "       (regex #\"^%s/\")%s)\n",
+                request, nodebug);
   cupsFilePrintf(fp,
                  "(allow file-write* file-read-data file-read-metadata\n"
                  "  (regex"
@@ -150,56 +201,160 @@ cupsdCreateProfile(int job_id)           /* I - Job ID or 0 for none */
                 " #\"^%s/\""           /* TempDir/... */
                 " #\"^%s$\""           /* CacheDir */
                 " #\"^%s/\""           /* CacheDir/... */
+                "))\n",
+                temp, temp, cache, cache);
+  /* Read common folders */
+  cupsFilePrintf(fp,
+                 "(allow file-read-data file-read-metadata\n"
+                 "  (regex"
+                 " #\"^/AppleInternal$\""
+                 " #\"^/AppleInternal/\""
+                 " #\"^/bin$\""                /* /bin */
+                 " #\"^/bin/\""                /* /bin/... */
+                 " #\"^/private$\""
+                 " #\"^/private/etc$\""
+                 " #\"^/private/etc/\""
+                 " #\"^/private/tmp$\""
+                 " #\"^/private/tmp/\""
+                 " #\"^/private/var$\""
+                 " #\"^/private/var/db$\""
+                 " #\"^/private/var/folders$\""
+                 " #\"^/private/var/lib$\""
+                 " #\"^/private/var/log$\""
+                 " #\"^/private/var/mysql$\""
+                 " #\"^/private/var/run$\""
+                 " #\"^/private/var/spool$\""
+                 " #\"^/private/var/tmp$\""
+                 " #\"^/private/var/tmp/\""
+                 " #\"^/usr/bin$\""    /* /usr/bin */
+                 " #\"^/usr/bin/\""    /* /usr/bin/... */
+                 " #\"^/usr/libexec/cups$\""   /* /usr/libexec/cups */
+                 " #\"^/usr/libexec/cups/\""   /* /usr/libexec/cups/... */
+                 " #\"^/usr/libexec/fax$\""    /* /usr/libexec/fax */
+                 " #\"^/usr/libexec/fax/\""    /* /usr/libexec/fax/... */
+                 " #\"^/usr/sbin$\""   /* /usr/sbin */
+                 " #\"^/usr/sbin/\""   /* /usr/sbin/... */
+                " #\"^/Library$\""     /* /Library */
+                " #\"^/Library/\""     /* /Library/... */
+                " #\"^/System$\""      /* /System */
+                " #\"^/System/\""      /* /System/... */
                 " #\"^%s/Library$\""   /* RequestRoot/Library */
                 " #\"^%s/Library/\""   /* RequestRoot/Library/... */
-                " #\"^/Library/Application Support/\""
-                " #\"^/Library/Caches/\""
-                " #\"^/Library/Preferences/\""
-                " #\"^/Library/Printers/.*/\""
-                " #\"^/Users/Shared/\""
+                " #\"^%s$\""           /* ServerBin */
+                " #\"^%s/\""           /* ServerBin/... */
+                " #\"^%s$\""           /* ServerRoot */
+                " #\"^%s/\""           /* ServerRoot/... */
+                " #\"^%s$\""           /* StateDir */
+                " #\"^%s/\""           /* StateDir/... */
                 "))\n",
-                temp, temp, cache, cache, request, request);
-  cupsFilePrintf(fp,
-                "(deny file-write*\n"
+                request, request, bin, bin, root, root, state, state);
+  if (Sandboxing == CUPSD_SANDBOXING_RELAXED)
+  {
+    /* Limited write access to /Library/Printers/... */
+    cupsFilePuts(fp,
+                "(allow file-write*\n"
                 "  (regex"
-                " #\"^/Library/Printers/PPDs$\""
-                " #\"^/Library/Printers/PPDs/\""
-                " #\"^/Library/Printers/PPD Plugins$\""
-                " #\"^/Library/Printers/PPD Plugins/\""
-                ")%s)\n", nodebug);
-  if (job_id)
+                " #\"^/Library/Printers/.*/\""
+                "))\n");
+    cupsFilePrintf(fp,
+                  "(deny file-write*\n"
+                  "  (regex"
+                  " #\"^/Library/Printers/PPDs$\""
+                  " #\"^/Library/Printers/PPDs/\""
+                  " #\"^/Library/Printers/PPD Plugins$\""
+                  " #\"^/Library/Printers/PPD Plugins/\""
+                  ")%s)\n", nodebug);
+  }
+  /* Allow execution of child processes as long as the programs are not in a user directory */
+  cupsFilePuts(fp, "(allow process*)\n");
+  cupsFilePuts(fp, "(deny process-exec (regex #\"^/Users/\"))\n");
+  if (RunUser && getenv("CUPS_TESTROOT"))
   {
-   /*
-    * Allow job filters to read the spool file(s)...
-    */
+    /* Allow source directory access in "make test" environment */
+    char       testroot[1024];         /* Root directory of test files */
+
+    cupsd_requote(testroot, getenv("CUPS_TESTROOT"), sizeof(testroot));
 
+    cupsFilePrintf(fp,
+                  "(allow file-write* file-read-data file-read-metadata\n"
+                  "  (regex"
+                  " #\"^%s$\""         /* CUPS_TESTROOT */
+                  " #\"^%s/\""         /* CUPS_TESTROOT/... */
+                  "))\n",
+                  testroot, testroot);
+    cupsFilePrintf(fp,
+                  "(allow process-exec\n"
+                  "  (regex"
+                  " #\"^%s/\""         /* CUPS_TESTROOT/... */
+                  "))\n",
+                  testroot);
+    cupsFilePrintf(fp, "(allow sysctl*)\n");
+  }
+  if (job_id)
+  {
+    /* Allow job filters to read the current job files... */
     cupsFilePrintf(fp,
                    "(allow file-read-data file-read-metadata\n"
-                   "  (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n",
+                   "       (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n",
                   request, job_id, job_id);
   }
   else
   {
-   /*
-    * Allow email notifications from notifiers...
-    */
-
+    /* Allow email notifications from notifiers... */
     cupsFilePuts(fp,
                 "(allow process-exec\n"
                 "  (literal \"/usr/sbin/sendmail\")\n"
-                "  (with no-sandbox)\n"
-                ")\n");
+                "  (with no-sandbox))\n");
+  }
+  /* Allow access to Bluetooth, USB, and notify_post. */
+  cupsFilePuts(fp, "(allow iokit*)\n");
+  cupsFilePuts(fp, "(allow distributed-notification-post)\n");
+  /* Allow outbound networking to local services */
+  cupsFilePuts(fp, "(allow network-outbound"
+                  "\n       (regex #\"^/private/var/run/\" #\"^/private/tmp/\" #\"^/private/var/tmp/\")");
+  for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+       lis;
+       lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+  {
+    if (httpAddrFamily(&(lis->address)) == AF_LOCAL)
+    {
+      httpAddrString(&(lis->address), domain, sizeof(domain));
+      cupsFilePrintf(fp, "\n       (literal \"%s\")", domain);
+    }
+  }
+  if (allow_networking)
+  {
+    /* Allow TCP and UDP networking off the machine... */
+    cupsFilePuts(fp, "\n       (remote tcp))\n");
+    cupsFilePuts(fp, "(allow network-bind)\n"); /* for LPD resvport */
+    cupsFilePuts(fp, "(allow network*\n"
+                    "       (local udp \"*:*\")\n"
+                    "       (remote udp \"*:*\"))\n");
+
+    /* Also allow access to device files... */
+    cupsFilePuts(fp, "(allow file-write* file-read-data file-read-metadata file-ioctl\n"
+                     "       (regex #\"^/dev/\"))\n");
+
+    /* And allow kernel extensions to be loaded, e.g., SMB */
+    cupsFilePuts(fp, "(allow system-kext-load)\n");
+  }
+  else
+  {
+    /* Only allow SNMP (UDP) and LPD (TCP) off the machine... */
+    cupsFilePuts(fp, ")\n");
+    cupsFilePuts(fp, "(allow network-outbound\n"
+                    "       (remote udp \"*:161\")\n"
+                    "       (remote tcp \"*:515\"))\n");
+    cupsFilePuts(fp, "(allow network-inbound\n"
+                    "       (local udp \"localhost:*\"))\n");
   }
-
   cupsFileClose(fp);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = \"%s\"",
-                  job_id, profile);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d,allow_networking=%d) = \"%s\"", job_id, allow_networking, profile);
   return ((void *)strdup(profile));
 
 #else
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = NULL",
-                  job_id);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d, allow_networking=%d) = NULL", job_id, allow_networking);
 
   return (NULL);
 #endif /* HAVE_SANDBOX_H */
@@ -262,10 +417,10 @@ cupsdEndProcess(int pid,          /* I - Process ID */
  */
 
 const char *                           /* O - Process name */
-cupsdFinishProcess(int  pid,           /* I - Process ID */
-                   char *name,         /* I - Name buffer */
-                  int  namelen,        /* I - Size of name buffer */
-                  int  *job_id)        /* O - Job ID pointer or NULL */
+cupsdFinishProcess(int    pid,         /* I - Process ID */
+                   char   *name,       /* I - Name buffer */
+                  size_t namelen,      /* I - Size of name buffer */
+                  int    *job_id)      /* O - Job ID pointer or NULL */
 {
   cupsd_proc_t key,                    /* Search key */
                *proc;                  /* Matching process */
@@ -290,10 +445,7 @@ cupsdFinishProcess(int  pid,               /* I - Process ID */
     strlcpy(name, "unknown", namelen);
   }
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                 "cupsdFinishProcess(pid=%d, name=%p, namelen=%d, "
-                 "job_id=%p(%d)) = \"%s\"", pid, name, namelen, job_id,
-                 job_id ? *job_id : 0, name);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishProcess(pid=%d, name=%p, namelen=" CUPS_LLFMT ", job_id=%p(%d)) = \"%s\"", pid, name, CUPS_LLCAST namelen, job_id, job_id ? *job_id : 0, name);
 
   return (name);
 }
@@ -320,20 +472,20 @@ cupsdStartProcess(
 {
   int          i;                      /* Looping var */
   const char   *exec_path = command;   /* Command to be exec'd */
-  char         *real_argv[107],        /* Real command-line arguments */
-               cups_exec[1024];        /* Path to "cups-exec" program */
+  char         *real_argv[110],        /* Real command-line arguments */
+               cups_exec[1024],        /* Path to "cups-exec" program */
+               user_str[16],           /* User string */
+               group_str[16],          /* Group string */
+               nice_str[16];           /* FilterNice string */
   uid_t                user;                   /* Command UID */
   cupsd_proc_t *proc;                  /* New process record */
-#ifdef HAVE_POSIX_SPAWN
+#if USE_POSIX_SPAWN
   posix_spawn_file_actions_t actions;  /* Spawn file actions */
   posix_spawnattr_t attrs;             /* Spawn attributes */
-  char         user_str[16],           /* User string */
-               group_str[16],          /* Group string */
-               nice_str[16];           /* FilterNice string */
-#endif /* HAVE_POSIX_SPAWN */
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+  sigset_t     defsignals;             /* Default signals */
+#elif defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
   struct sigaction action;             /* POSIX signal handler */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+#endif /* USE_POSIX_SPAWN */
 #if defined(__APPLE__)
   char         processPath[1024],      /* CFProcessPath environment variable */
                linkpath[1024];         /* Link path for symlinks... */
@@ -366,7 +518,7 @@ cupsdStartProcess(
   if (envp)
   {
    /*
-    * Add special voodoo magic for OS X - this allows OS X programs to access
+    * Add special voodoo magic for macOS - this allows macOS programs to access
     * their bundle resources properly...
     */
 
@@ -397,28 +549,31 @@ cupsdStartProcess(
   * Use helper program when we have a sandbox profile...
   */
 
-#ifndef HAVE_POSIX_SPAWN
+#if !USE_POSIX_SPAWN
   if (profile)
-#endif /* !HAVE_POSIX_SPAWN */
+#endif /* !USE_POSIX_SPAWN */
   {
     snprintf(cups_exec, sizeof(cups_exec), "%s/daemon/cups-exec", ServerBin);
-    snprintf(user_str, sizeof(user_str), "%d", User);
+    snprintf(user_str, sizeof(user_str), "%d", user);
     snprintf(group_str, sizeof(group_str), "%d", Group);
     snprintf(nice_str, sizeof(nice_str), "%d", FilterNice);
 
     real_argv[0] = cups_exec;
-    real_argv[1] = profile;
-    real_argv[2] = user_str;
-    real_argv[3] = group_str;
+    real_argv[1] = (char *)"-g";
+    real_argv[2] = group_str;
+    real_argv[3] = (char *)"-n";
     real_argv[4] = nice_str;
-    real_argv[5] = (char *)command;
+    real_argv[5] = (char *)"-u";
+    real_argv[6] = user_str;
+    real_argv[7] = profile ? profile : "none";
+    real_argv[8] = (char *)command;
 
     for (i = 0;
-         i < (int)(sizeof(real_argv) / sizeof(real_argv[0]) - 7) && argv[i];
+         i < (int)(sizeof(real_argv) / sizeof(real_argv[0]) - 10) && argv[i];
         i ++)
-      real_argv[i + 6] = argv[i];
+      real_argv[i + 9] = argv[i];
 
-    real_argv[i + 6] = NULL;
+    real_argv[i + 9] = NULL;
 
     argv      = real_argv;
     exec_path = cups_exec;
@@ -432,21 +587,28 @@ cupsdStartProcess(
       cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: argv[%d] = \"%s\"", i, argv[i]);
   }
 
-#ifdef HAVE_POSIX_SPAWN
+#if USE_POSIX_SPAWN
  /*
   * Setup attributes and file actions for the spawn...
   */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Setting spawn attributes.");
+  sigemptyset(&defsignals);
+  sigaddset(&defsignals, SIGTERM);
+  sigaddset(&defsignals, SIGCHLD);
+  sigaddset(&defsignals, SIGPIPE);
+
   posix_spawnattr_init(&attrs);
   posix_spawnattr_setflags(&attrs, POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_SETSIGDEF);
+  posix_spawnattr_setpgroup(&attrs, 0);
+  posix_spawnattr_setsigdefault(&attrs, &defsignals);
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartProcess: Setting file actions.");
   posix_spawn_file_actions_init(&actions);
   if (infd != 0)
   {
     if (infd < 0)
-      posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_WRONLY, 0);
+      posix_spawn_file_actions_addopen(&actions, 0, "/dev/null", O_RDONLY, 0);
     else
       posix_spawn_file_actions_adddup2(&actions, infd, 0);
   }
@@ -648,7 +810,7 @@ cupsdStartProcess(
   }
 
   cupsdReleaseSignals();
-#endif /* HAVE_POSIX_SPAWN */
+#endif /* USE_POSIX_SPAWN */
 
   if (*pid)
   {
@@ -716,7 +878,7 @@ cupsd_requote(char       *dst,              /* I - Destination buffer */
     if (ch == '/' && !*src)
       break;                           /* Don't add trailing slash */
 
-    if (strchr(".?*()[]^$\\", ch))
+    if (strchr(".?*()[]^$\\\"", ch))
       *dstptr++ = '\\';
 
     *dstptr++ = (char)ch;
@@ -727,8 +889,3 @@ cupsd_requote(char       *dst,              /* I - Destination buffer */
   return (dst);
 }
 #endif /* HAVE_SANDBOX_H */
-
-
-/*
- * End of "$Id$".
- */