#include <cups/string-private.h>
#include <cups/file.h>
#include <unistd.h>
#include <fcntl.h>
#include <grp.h>
#include <sys/stat.h>
#ifdef HAVE_SANDBOX_H
# include <sandbox.h>
# ifndef SANDBOX_NAMED_EXTERNAL
# define SANDBOX_NAMED_EXTERNAL 0x0003
# endif
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
static void usage(void) __attribute__((noreturn));
int
main(int argc,
char *argv[])
{
int i;
const char *opt;
uid_t uid = getuid();
gid_t gid = getgid();
int niceval = 0;
#ifdef HAVE_SANDBOX_H
char *sandbox_error = NULL;
#endif
for (i = 1; i < argc; i ++)
{
if (argv[i][0] == '-')
{
for (opt = argv[i] + 1; *opt; opt ++)
{
switch (*opt)
{
case 'g' :
i ++;
if (i >= argc)
usage();
gid = (gid_t)atoi(argv[i]);
break;
case 'n' :
i ++;
if (i >= argc)
usage();
niceval = atoi(argv[i]);
break;
case 'u' :
i ++;
if (i >= argc)
usage();
uid = (uid_t)atoi(argv[i]);
break;
default :
fprintf(stderr, "cups-exec: Unknown option '-%c'.\n", *opt);
usage();
}
}
}
else
break;
}
if ((i + 3) > argc)
{
fputs("cups-exec: Insufficient arguments.\n", stderr);
usage();
}
fcntl(3, F_SETFL, O_NDELAY);
fcntl(4, F_SETFL, O_NDELAY);
if (uid)
nice(niceval);
if (!getuid())
{
if (setgid(gid))
exit(errno + 100);
if (setgroups(1, &gid))
exit(errno + 100);
if (uid && setuid(uid))
exit(errno + 100);
}
umask(077);
#ifdef HAVE_SANDBOX_H
if (strcmp(argv[i], "none") &&
sandbox_init(argv[i], SANDBOX_NAMED_EXTERNAL, &sandbox_error))
{
cups_file_t *fp;
char line[1024];
int linenum = 0;
fprintf(stderr, "DEBUG: sandbox_init failed: %s (%s)\n", sandbox_error,
strerror(errno));
sandbox_free_error(sandbox_error);
if ((fp = cupsFileOpen(argv[i], "r")) != NULL)
{
while (cupsFileGets(fp, line, sizeof(line)))
{
linenum ++;
fprintf(stderr, "DEBUG: %4d %s\n", linenum, line);
}
cupsFileClose(fp);
}
return (100 + EINVAL);
}
#endif
execv(argv[i + 1], argv + i + 2);
fprintf(stderr, "DEBUG: execv failed: %s\n", strerror(errno));
return (errno + 100);
}
static void
usage(void)
{
fputs("Usage: cups-exec [-g gid] [-n nice-value] [-u uid] /path/to/profile /path/to/program argv0 argv1 ... argvN\n", stderr);
exit(1);
}