|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Sandbox helper for CUPS.
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* Copyright 2007-2014 by Apple Inc.
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* These coded instructions, statements, and computer programs are the
|
|
Packit |
2fc92b |
* property of Apple Inc. and are protected by Federal copyright
|
|
Packit |
2fc92b |
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
|
|
Packit |
2fc92b |
* which should have been included with this file. If this file is
|
|
Packit |
2fc92b |
* missing or damaged, see the license at "http://www.cups.org/".
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* Usage:
|
|
Packit |
2fc92b |
*
|
|
Packit |
2fc92b |
* cups-exec /path/to/profile [-u UID] [-g GID] [-n NICE] /path/to/program argv0 argv1 ... argvN
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Include necessary headers...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
#include <cups/string-private.h>
|
|
Packit |
2fc92b |
#include <cups/file.h>
|
|
Packit |
2fc92b |
#include <unistd.h>
|
|
Packit |
2fc92b |
#include <fcntl.h>
|
|
Packit |
2fc92b |
#include <grp.h>
|
|
Packit |
2fc92b |
#include <sys/stat.h>
|
|
Packit |
2fc92b |
#ifdef HAVE_SANDBOX_H
|
|
Packit |
2fc92b |
# include <sandbox.h>
|
|
Packit |
2fc92b |
# ifndef SANDBOX_NAMED_EXTERNAL
|
|
Packit |
2fc92b |
# define SANDBOX_NAMED_EXTERNAL 0x0003
|
|
Packit |
2fc92b |
# endif /* !SANDBOX_NAMED_EXTERNAL */
|
|
Packit |
2fc92b |
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
Packit |
2fc92b |
#endif /* HAVE_SANDBOX_H */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Local functions...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
static void usage(void) __attribute__((noreturn));
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'main()' - Apply sandbox profile and execute program.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
int /* O - Exit status */
|
|
Packit |
2fc92b |
main(int argc, /* I - Number of command-line args */
|
|
Packit |
2fc92b |
char *argv[]) /* I - Command-line arguments */
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
int i; /* Looping var */
|
|
Packit |
2fc92b |
const char *opt; /* Current option character */
|
|
Packit |
2fc92b |
uid_t uid = getuid(); /* UID */
|
|
Packit |
2fc92b |
gid_t gid = getgid(); /* GID */
|
|
Packit |
2fc92b |
int niceval = 0; /* Nice value */
|
|
Packit |
2fc92b |
#ifdef HAVE_SANDBOX_H
|
|
Packit |
2fc92b |
char *sandbox_error = NULL; /* Sandbox error, if any */
|
|
Packit |
2fc92b |
#endif /* HAVE_SANDBOX_H */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Parse command-line...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
for (i = 1; i < argc; i ++)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
if (argv[i][0] == '-')
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
for (opt = argv[i] + 1; *opt; opt ++)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
switch (*opt)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
case 'g' : /* -g gid */
|
|
Packit |
2fc92b |
i ++;
|
|
Packit |
2fc92b |
if (i >= argc)
|
|
Packit |
2fc92b |
usage();
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
gid = (gid_t)atoi(argv[i]);
|
|
Packit |
2fc92b |
break;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
case 'n' : /* -n nice-value */
|
|
Packit |
2fc92b |
i ++;
|
|
Packit |
2fc92b |
if (i >= argc)
|
|
Packit |
2fc92b |
usage();
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
niceval = atoi(argv[i]);
|
|
Packit |
2fc92b |
break;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
case 'u' : /* -g gid */
|
|
Packit |
2fc92b |
i ++;
|
|
Packit |
2fc92b |
if (i >= argc)
|
|
Packit |
2fc92b |
usage();
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
uid = (uid_t)atoi(argv[i]);
|
|
Packit |
2fc92b |
break;
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
default :
|
|
Packit |
2fc92b |
fprintf(stderr, "cups-exec: Unknown option '-%c'.\n", *opt);
|
|
Packit |
2fc92b |
usage();
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
else
|
|
Packit |
2fc92b |
break;
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Check that we have enough arguments...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if ((i + 3) > argc)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
fputs("cups-exec: Insufficient arguments.\n", stderr);
|
|
Packit |
2fc92b |
usage();
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Make sure side and back channel FDs are non-blocking...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
fcntl(3, F_SETFL, O_NDELAY);
|
|
Packit |
2fc92b |
fcntl(4, F_SETFL, O_NDELAY);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Change UID, GID, and nice value...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (uid)
|
|
Packit |
2fc92b |
nice(niceval);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (!getuid())
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
if (setgid(gid))
|
|
Packit |
2fc92b |
exit(errno + 100);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (setgroups(1, &gid))
|
|
Packit |
2fc92b |
exit(errno + 100);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (uid && setuid(uid))
|
|
Packit |
2fc92b |
exit(errno + 100);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
umask(077);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
#ifdef HAVE_SANDBOX_H
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Run in a separate security profile...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if (strcmp(argv[i], "none") &&
|
|
Packit |
2fc92b |
sandbox_init(argv[i], SANDBOX_NAMED_EXTERNAL, &sandbox_error))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
cups_file_t *fp; /* File */
|
|
Packit |
2fc92b |
char line[1024]; /* Line from file */
|
|
Packit |
2fc92b |
int linenum = 0; /* Line number in file */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
fprintf(stderr, "DEBUG: sandbox_init failed: %s (%s)\n", sandbox_error,
|
|
Packit |
2fc92b |
strerror(errno));
|
|
Packit |
2fc92b |
sandbox_free_error(sandbox_error);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
if ((fp = cupsFileOpen(argv[i], "r")) != NULL)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
while (cupsFileGets(fp, line, sizeof(line)))
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
linenum ++;
|
|
Packit |
2fc92b |
fprintf(stderr, "DEBUG: %4d %s\n", linenum, line);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
cupsFileClose(fp);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
return (100 + EINVAL);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
#endif /* HAVE_SANDBOX_H */
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* Execute the program...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
execv(argv[i + 1], argv + i + 2);
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* If we get here, execv() failed...
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
fprintf(stderr, "DEBUG: execv failed: %s\n", strerror(errno));
|
|
Packit |
2fc92b |
return (errno + 100);
|
|
Packit |
2fc92b |
}
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
/*
|
|
Packit |
2fc92b |
* 'usage()' - Show program usage.
|
|
Packit |
2fc92b |
*/
|
|
Packit |
2fc92b |
|
|
Packit |
2fc92b |
static void
|
|
Packit |
2fc92b |
usage(void)
|
|
Packit |
2fc92b |
{
|
|
Packit |
2fc92b |
fputs("Usage: cups-exec [-g gid] [-n nice-value] [-u uid] /path/to/profile /path/to/program argv0 argv1 ... argvN\n", stderr);
|
|
Packit |
2fc92b |
exit(1);
|
|
Packit |
2fc92b |
}
|