]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge Mac OS X seatbelt support onto trunk.
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 19 Dec 2007 19:19:20 +0000 (19:19 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 19 Dec 2007 19:19:20 +0000 (19:19 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@7145 7a7537e8-13f0-0310-91df-b6672ffda945

12 files changed:
CHANGES.txt
config-scripts/cups-common.m4
config.h.in
scheduler/client.c
scheduler/cupsd.h
scheduler/dirsvc.c
scheduler/ipp.c
scheduler/job.c
scheduler/job.h
scheduler/process.c
scheduler/server.c
scheduler/subscriptions.c

index ca5acc926fd4a4c3acd4055fce24fba57bca30d8..ebee69611e73f0321a01de0c0956ac11f6c1b5bf 100644 (file)
@@ -1,8 +1,10 @@
-CHANGES.txt - 2007-12-07
+CHANGES.txt - 2007-12-19
 ------------------------
 
 CHANGES IN CUPS V1.4b1
 
+       - The scheduler now sandboxes child processes when
+         possible.
        - The Cancel-Job operation now supports a purge-job
          attriibute to purge a specified job.
        - ppdEmit* and ppdCollect* now use the NonUIOrderDependency
index cf31ef50ea6923fdf3dfe1a3302c9e84b881e93a..2ebfeb240c76c8aa5d9f3f506484439c055dcf69 100644 (file)
@@ -237,6 +237,9 @@ case $uname in
                        CUPS_DEFAULT_PRINTADMIN_AUTH="@AUTHKEY(system.print.admin) @admin @lpadmin"
                        CUPS_SYSTEM_AUTHKEY="SystemGroupAuthKey system.preferences"])
                AC_CHECK_HEADER(Security/SecBasePriv.h,AC_DEFINE(HAVE_SECBASEPRIV_H))
+
+               dnl Check for sandbox/Seatbelt support
+               AC_CHECK_HEADER(sandbox.h,AC_DEFINE(HAVE_SANDBOX_H))
                 ;;
 
        Linux*)
index 79a45d9dab583a5064ad43513fef8d359bc488b7..6c8fea11d3a72a9a1bd7e28f90d1f0dd6da96629 100644 (file)
 #undef HAVE_REMOVEFILE
 
 
+/*
+ * Do we have <sandbox.h>?
+ */
+
+#undef HAVE_SANDBOX_H
+
+
 #endif /* !_CUPS_CONFIG_H_ */
 
 /*
index e0c665e05069c7d25c1526462dc050a4e7d1b74b..7d6ccb8e79b5c1d587e64d7132dd3dd8a4332c3d 100644 (file)
@@ -3847,7 +3847,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
     envp[envc++] = home;
     envp[envc]   = NULL;
 
-    if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, &pid))
+    if (!cupsdStartProcess(command, argv, envp, -1, -1, -1, -1, -1, 1, NULL,
+                           &pid))
     {
       unlink(seedfile);
       return (0);
@@ -3924,7 +3925,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
 
   infofd = open(infofile, O_RDONLY);
 
-  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid))
+  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
+                         &pid))
   {
     close(infofd);
     unlink(infofile);
@@ -4157,7 +4159,8 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
 
   infofd = open(infofile, O_RDONLY);
 
-  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, &pid))
+  if (!cupsdStartProcess(command, argv, envp, infofd, -1, -1, -1, -1, 1, NULL,
+                         &pid))
   {
     close(infofd);
     unlink(infofile);
@@ -4557,7 +4560,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   */
 
   if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1],
-                       -1, -1, root, &pid) < 0)
+                       -1, -1, root, DefaultProfile, &pid) < 0)
   {
    /*
     * Error - can't fork!
index 07191fe2383835675964d9afe88419a66e6c0add..736d0142d843b86defa8da3cb20269789810f984 100644 (file)
@@ -160,6 +160,8 @@ VAR time_t          ReloadTime      VALUE(0);
                                        /* Time of reload request... */
 VAR int                        NeedReload      VALUE(RELOAD_ALL);
                                        /* Need to load configuration? */
+VAR void               *DefaultProfile VALUE(0);
+                                       /* Default security profile */
 
 #ifdef HAVE_GSSAPI
 VAR krb5_context       KerberosContext;/* Kerberos context for credentials */
@@ -208,12 +210,14 @@ __attribute__ ((__format__ (__printf__, 2, 3)))
 #endif /* __GNUC__ */
 ;
 
+extern void    *cupsdCreateProfile(int job_id);
+extern void    cupsdDestroyProfile(void *profile);
 extern int     cupsdEndProcess(int pid, int force);
 extern const char *cupsdFinishProcess(int pid, char *name, int namelen);
 extern int     cupsdStartProcess(const char *command, char *argv[],
                                  char *envp[], int infd, int outfd,
                                  int errfd, int backfd, int sidefd,
-                                 int root, int *pid);
+                                 int root, void *profile, int *pid);
 
 extern int     cupsdAddSelect(int fd, cupsd_selfunc_t read_cb,
                               cupsd_selfunc_t write_cb, void *data);
index d1ea1498d39fcbf1aa708381e030fa040c7a714c..d16756aca8b2ca8803756ffa7bdd39382c678c0b 100644 (file)
@@ -1248,7 +1248,7 @@ cupsdStartPolling(void)
     argv[1] = pollp->hostname;
 
     if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, -1,
-                          0, &(pollp->pid)) < 0)
+                          0, DefaultProfile, &(pollp->pid)) < 0)
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "cupsdStartPolling: Unable to fork polling daemon - %s",
@@ -3900,7 +3900,8 @@ update_lpd(int onoff)                     /* - 1 = turn on, 0 = turn off */
     argv[3] = LPDConfigFile + 10;
     argv[4] = NULL;
 
-    cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid);
+    cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
+                      NULL, &pid);
   }
 }
 
@@ -4015,7 +4016,8 @@ update_smb(int onoff)                     /* I - 1 = turn on, 0 = turn off */
     argv[3] = SMBConfigFile + 10;
     argv[4] = NULL;
 
-    cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid);
+    cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1,
+                      NULL, &pid);
   }
 }
 
index a97bd961c05d1fd71d47fa1debf7278efab5f6f4..044d53e58780d7f1cd0e28f526db9a77a484f079 100644 (file)
@@ -4293,10 +4293,11 @@ copy_model(cupsd_client_t *con,         /* I - Client connection */
                   "copy_model: Running \"cups-driverd cat %s\"...", from);
 
   if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1],
-                         -1, -1, 0, &temppid))
+                         -1, -1, 0, DefaultProfile, &temppid))
   {
     close(tempfd);
     unlink(tempfile);
+
     return (-1);
   }
 
index 4cd747906c9310decbb4463392add7ba564eb81c..9063534558bc50efe53346302d47be4a30587586 100644 (file)
@@ -1710,6 +1710,9 @@ cupsdStopJob(cupsd_job_t *job,            /* I - Job */
     job->backend = 0;
   }
 
+  cupsdDestroyProfile(job->profile);
+  job->profile = NULL;
+
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Job %d] Closing print pipes [ %d %d ]...",
                   job->id, job->print_pipes[0], job->print_pipes[1]);
 
@@ -3182,6 +3185,9 @@ start_job(cupsd_job_t     *job,           /* I - Job ID */
   job->status = 0;
   memset(job->filters, 0, sizeof(job->filters));
 
+  if (!job->profile)
+    job->profile = cupsdCreateProfile(job->id);
+
   for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
        filter;
        i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
@@ -3292,7 +3298,7 @@ start_job(cupsd_job_t     *job,           /* I - Job ID */
     pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
                             filterfds[slot][1], job->status_pipes[1],
                            job->back_pipes[0], job->side_pipes[0], 0,
-                           job->filters + i);
+                           job->profile, job->filters + i);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "[Job %d] start_job: Closing filter pipes for slot %d "
@@ -3364,7 +3370,7 @@ start_job(cupsd_job_t     *job,           /* I - Job ID */
       pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
                              filterfds[slot][1], job->status_pipes[1],
                              job->back_pipes[1], job->side_pipes[1],
-                             backroot, &(job->backend));
+                             backroot, job->profile, &(job->backend));
 
       if (pid == 0)
       {
index 6585d5d841b67d9e9beb1decf827457fa2a41825..11ae2d144cf3730261b908351ddd130947b89698 100644 (file)
@@ -56,6 +56,7 @@ typedef struct cupsd_job_s
   char                 *auth_username, /* AUTH_USERNAME environment variable, if any */
                        *auth_domain,   /* AUTH_DOMAIN environment variable, if any */
                        *auth_password; /* AUTH_PASSWORD environment variable, if any */
+  void                 *profile;       /* Security profile */
 #ifdef HAVE_GSSAPI
   krb5_ccache          ccache;         /* Kerberos credential cache */
   char                 *ccname;        /* KRB5CCNAME environment variable */
index 5c86bcbbab004f483bb7a22643248ab8bac218c3..83cb948ef5a7193863f841a37e742ba2a59b2475 100644 (file)
  *
  * 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 */
 
 
 /*
@@ -54,6 +61,85 @@ 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 */
+  size_t       requestlen;             /* Length of RequestRoot */
+
+
+  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\" #\"^/etc\" #\"^/usr/local/etc\" "
+                "#\"^/Library\" #\"^/System\"))\n", root);
+  cupsFilePrintf(fp,
+                 "(allow file-write* file-read-data file-read-metadata\n"
+                 "  (regex #\"^%s$\" #\"^%s/\" #\"^%s$\" #\"^%s/\"))\n",
+                temp, cache, temp, 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);
+
+  cupsFileClose(fp);
+
+  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)
+  {
+    unlink((char *)profile);
+    free(profile);
+  }
+#endif /* HAVE_SANDBOX_H */
+}
 
 
 /*
@@ -114,6 +200,7 @@ cupsdStartProcess(
     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 */
@@ -289,6 +376,24 @@ cupsdStartProcess(
 
     cupsdReleaseSignals();
 
+#ifdef HAVE_SANDBOX_H
+   /*
+    * Run in a separate security profile...
+    */
+
+    if (profile)
+    {
+      char *error;                     /* 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 */
+
    /*
     * Execute the command; if for some reason this doesn't work,
     * return the error code...
@@ -349,6 +454,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$".
  */
index a16c3567e1a9be511534fc175c22268b4d1c8a72..27d083f1eb89602e94961dbd505d169842cfb6ef 100644 (file)
@@ -79,6 +79,12 @@ cupsdStartServer(void)
   gnutls_global_init();
 #endif /* HAVE_LIBSSL */
 
+ /*
+  * Create the default security profile...
+  */
+
+  DefaultProfile = cupsdCreateProfile(0);
+
  /*
   * Startup all the networking stuff...
   */
@@ -155,6 +161,16 @@ cupsdStopServer(void)
     CGIPipes[1] = -1;
   }
 
+#ifdef HAVE_NOTIFY_POST
+ /*
+  * Send one last notification as the server shuts down.
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG,
+                  "notify_post(\"com.apple.printerListChange\") last");
+  notify_post("com.apple.printerListChange");
+#endif /* HAVE_NOTIFY_POST */
+
  /*
   * Close all log files...
   */
@@ -180,15 +196,12 @@ cupsdStopServer(void)
     PageFile = NULL;
   }
 
-#ifdef HAVE_NOTIFY_POST
  /*
-  * Send one last notification as the server shuts down.
+  * Delete the default security profile...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG,
-                  "notify_post(\"com.apple.printerListChange\") last");
-  notify_post("com.apple.printerListChange");
-#endif /* HAVE_NOTIFY_POST */
+  cupsdDestroyProfile(DefaultProfile);
+  DefaultProfile = NULL;
 
   started = 0;
 }
index c38ea2ca0a9070165aca3a317419a0f0dcd921be..ce2a2ade5663317b091bcc4a72f844aa47474eeb 100644 (file)
@@ -1565,7 +1565,7 @@ cupsd_start_notifier(
   */
 
   if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1],
-                       -1, -1, 0, &pid) < 0)
+                       -1, -1, 0, DefaultProfile, &pid) < 0)
   {
    /*
     * Error - can't fork!