-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
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*)
#undef HAVE_REMOVEFILE
+/*
+ * Do we have <sandbox.h>?
+ */
+
+#undef HAVE_SANDBOX_H
+
+
#endif /* !_CUPS_CONFIG_H_ */
/*
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);
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);
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);
*/
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!
/* 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 */
#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);
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",
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);
}
}
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);
}
}
"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);
}
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]);
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))
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 "
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)
{
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 */
*
* 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 */
/*
*/
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 */
+}
/*
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 */
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...
}
+#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$".
*/
gnutls_global_init();
#endif /* HAVE_LIBSSL */
+ /*
+ * Create the default security profile...
+ */
+
+ DefaultProfile = cupsdCreateProfile(0);
+
/*
* Startup all the networking stuff...
*/
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...
*/
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;
}
*/
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!