Blame scheduler/cups-exec.c

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
}