]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/process.c
Merge changes from CUPS 1.4svn-r7696.
[thirdparty/cups.git] / scheduler / process.c
index 03cdbd9290618c02dd4d28789bf8861cfa4c2b3a..b0481296c78962e9fe7c8fae6b4404015d44b686 100644 (file)
@@ -1,32 +1,26 @@
 /*
- * "$Id$"
+ * "$Id: process.c 7256 2008-01-25 00:48:54Z mike $"
  *
  *   Process management routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 2007 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products 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 missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   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/".
  *
  * Contents:
  *
- *   cupsdEndProcess()    - End a process.
- *   cupsdFinishProcess() - Finish a process and get its name.
- *   cupsdStartProcess()  - Start a process.
- *   compare_procs()      - Compare two processes.
+ *   cupsdCreateProfile()  - Create an execution profile for a subprocess.
+ *   cupsdDestroyProfile() - Delete an execution profile.
+ *   cupsdEndProcess()     - End a process.
+ *   cupsdFinishProcess()  - Finish a process and get its name.
+ *   cupsdStartProcess()   - Start a process.
+ *   compare_procs()       - Compare two processes.
+ *   cupsd_requote()       - Make a regular-expression version of a string.
  */
 
 /*
 
 #include "cupsd.h"
 #include <grp.h>
-#if defined(__APPLE__)
+#ifdef __APPLE__
 #  include <libgen.h>
 #endif /* __APPLE__ */ 
+#ifdef HAVE_SANDBOX_H
+#  define __APPLE_API_PRIVATE
+#  include <sandbox.h>
+#endif /* HAVE_SANDBOX_H */
 
 
 /*
@@ -63,6 +61,89 @@ static cups_array_t  *process_array = NULL;
  */
 
 static int     compare_procs(cupsd_proc_t *a, cupsd_proc_t *b);
+#ifdef HAVE_SANDBOX_H
+static char    *cupsd_requote(char *dst, const char *src, size_t dstsize);
+#endif /* HAVE_SANDBOX_H */
+
+
+/*
+ * 'cupsdCreateProfile()' - Create an execution profile for a subprocess.
+ */
+
+void *                                 /* O - Profile or NULL on error */
+cupsdCreateProfile(int job_id)         /* I - Job ID or 0 for none */
+{
+#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 */
+
+
+  if ((fp = cupsTempFile2(profile, sizeof(profile))) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create security profile: %s",
+                    strerror(errno));
+    return (NULL);
+  }
+
+  cupsd_requote(cache, CacheDir, sizeof(cache));
+  cupsd_requote(request, RequestRoot, sizeof(request));
+  cupsd_requote(root, ServerRoot, sizeof(root));
+  cupsd_requote(temp, TempDir, sizeof(temp));
+
+  cupsFilePuts(fp, "(version 1)\n");
+  cupsFilePuts(fp, "(debug deny)\n");
+  cupsFilePuts(fp, "(allow default)\n");
+  cupsFilePrintf(fp,
+                 "(deny file-write* file-read-data file-read-metadata\n"
+                 "  (regex #\"^%s/\"))\n", request);
+  cupsFilePrintf(fp,
+                 "(deny file-write*\n"
+                 "  (regex #\"^%s\" #\"^/private/etc\" #\"^/usr/local/etc\" "
+                "#\"^/Library\" #\"^/System\" #\"^/Users\"))\n", root);
+  cupsFilePrintf(fp,
+                 "(allow file-write* file-read-data file-read-metadata\n"
+                 "  (regex #\"^%s$\" #\"^%s/\" #\"^%s$\" #\"^%s/\" "
+                "#\"^/Library/Caches/\"))\n",
+                temp, temp, cache, cache);
+  if (job_id)
+    cupsFilePrintf(fp,
+                   "(allow file-read-data file-read-metadata\n"
+                   "  (regex #\"^%s/([ac]%05d|d%05d-[0-9][0-9][0-9])$\"))\n",
+                  request, job_id, job_id);
+
+  cupsFileClose(fp);
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCreateProfile(job_id=%d) = \"%s\"",
+                  job_id, profile);
+  return ((void *)strdup(profile));
+#else
+
+  return (NULL);
+#endif /* HAVE_SANDBOX_H */
+}
+
+
+/*
+ * 'cupsdDestroyProfile()' - Delete an execution profile.
+ */
+
+void
+cupsdDestroyProfile(void *profile)     /* I - Profile */
+{
+#ifdef HAVE_SANDBOX_H
+  if (profile)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeleteProfile(profile=\"%s\")",
+                    (char *)profile);
+    unlink((char *)profile);
+    free(profile);
+  }
+#endif /* HAVE_SANDBOX_H */
+}
 
 
 /*
@@ -121,7 +202,9 @@ cupsdStartProcess(
     int        outfd,                  /* I - Standard output file descriptor */
     int        errfd,                  /* I - Standard error file descriptor */
     int        backfd,                 /* I - Backchannel file descriptor */
+    int        sidefd,                 /* I - Sidechannel file descriptor */
     int        root,                   /* I - Run as root? */
+    void       *profile,               /* I - Security profile to use */
     int        *pid)                   /* O - Process ID */
 {
   cupsd_proc_t *proc;                  /* New process record */
@@ -139,6 +222,14 @@ cupsdStartProcess(
                   "cupsdStartProcess(\"%s\", %p, %p, %d, %d, %d)",
                   command, argv, envp, infd, outfd, errfd);
 
+  if (access(command, X_OK))
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to execute %s: %s", command,
+                    strerror(errno));
+    *pid = 0;
+    return (0);
+  }
+
 #if defined(__APPLE__)
   if (envp)
   {
@@ -161,7 +252,7 @@ cupsdStartProcess(
                 linkpath);
       else
        snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
-                dirname(command), linkpath);
+                dirname((char *)command), linkpath);
     }
     else
       snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", command);
@@ -217,15 +308,39 @@ cupsdStartProcess(
         open("/dev/null", O_RDWR);
       fcntl(3, F_SETFL, O_NDELAY);
     }
+    if (sidefd != 4 && sidefd > 0)
+    {
+      close(4);
+      dup(sidefd);
+      fcntl(4, F_SETFL, O_NDELAY);
+    }
 
    /*
     * Change the priority of the process based on the FilterNice setting.
-    * (this is not done for backends...)
+    * (this is not done for root processes...)
     */
 
     if (!root)
       nice(FilterNice);
 
+#ifdef HAVE_SANDBOX_H
+   /*
+    * Run in a separate security profile...
+    */
+
+    if (profile)
+    {
+      char *error = NULL;              /* Sandbox error, if any */
+
+      if (sandbox_init((char *)profile, SANDBOX_NAMED_EXTERNAL, &error))
+      {
+        fprintf(stderr, "ERROR: sandbox_init failed: %s (%s)\n", error,
+               strerror(errno));
+       sandbox_free_error(error);
+      }
+    }
+#endif /* HAVE_SANDBOX_H */
+
    /*
     * Change user to something "safe"...
     */
@@ -343,6 +458,41 @@ compare_procs(cupsd_proc_t *a,             /* I - First process */
 }
 
 
+#ifdef HAVE_SANDBOX_H
+/*
+ * 'cupsd_requote()' - Make a regular-expression version of a string.
+ */
+
+static char *                          /* O - Quoted string */
+cupsd_requote(char       *dst,         /* I - Destination buffer */
+              const char *src,         /* I - Source string */
+             size_t     dstsize)       /* I - Size of destination buffer */
+{
+  int  ch;                             /* Current character */
+  char *dstptr,                        /* Current position in buffer */
+       *dstend;                        /* End of destination buffer */
+
+
+  dstptr = dst;
+  dstend = dst + dstsize - 2;
+
+  while (*src && dstptr < dstend)
+  {
+    ch = *src++;
+
+    if (strchr(".?*()[]^$\\", ch))
+      *dstptr++ = '\\';
+
+    *dstptr++ = ch;
+  }
+
+  *dstptr = '\0';
+
+  return (dst);
+}
+#endif /* HAVE_SANDBOX_H */
+
+
 /*
- * End of "$Id$".
+ * End of "$Id: process.c 7256 2008-01-25 00:48:54Z mike $".
  */