Imported Upstream version 2.2.0
[platform/upstream/cups.git] / scheduler / cups-exec.c
1 /*
2  * Sandbox helper for CUPS.
3  *
4  * Copyright 2007-2014 by Apple Inc.
5  *
6  * These coded instructions, statements, and computer programs are the
7  * property of Apple Inc. and are protected by Federal copyright
8  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
9  * which should have been included with this file.  If this file is
10  * file is missing or damaged, see the license at "http://www.cups.org/".
11  *
12  * Usage:
13  *
14  *     cups-exec /path/to/profile [-u UID] [-g GID] [-n NICE] /path/to/program argv0 argv1 ... argvN
15  */
16
17 /*
18  * Include necessary headers...
19  */
20
21 #include <cups/string-private.h>
22 #include <cups/file.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <grp.h>
26 #include <sys/stat.h>
27 #ifdef HAVE_SANDBOX_H
28 #  include <sandbox.h>
29 #  ifndef SANDBOX_NAMED_EXTERNAL
30 #    define SANDBOX_NAMED_EXTERNAL  0x0003
31 #  endif /* !SANDBOX_NAMED_EXTERNAL */
32 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
33 #endif /* HAVE_SANDBOX_H */
34
35
36 /*
37  * Local functions...
38  */
39
40 static void     usage(void) __attribute__((noreturn));
41
42
43 /*
44  * 'main()' - Apply sandbox profile and execute program.
45  */
46
47 int                                     /* O - Exit status */
48 main(int  argc,                         /* I - Number of command-line args */
49      char *argv[])                      /* I - Command-line arguments */
50 {
51   int           i;                      /* Looping var */
52   const char    *opt;                   /* Current option character */
53   uid_t         uid = getuid();         /* UID */
54   gid_t         gid = getgid();         /* GID */
55   int           niceval = 0;            /* Nice value */
56 #ifdef HAVE_SANDBOX_H
57   char          *sandbox_error = NULL;  /* Sandbox error, if any */
58 #endif /* HAVE_SANDBOX_H */
59
60
61  /*
62   * Parse command-line...
63   */
64
65   for (i = 1; i < argc; i ++)
66   {
67     if (argv[i][0] == '-')
68     {
69       for (opt = argv[i] + 1; *opt; opt ++)
70       {
71         switch (*opt)
72         {
73           case 'g' : /* -g gid */
74               i ++;
75               if (i >= argc)
76                 usage();
77
78               gid = (gid_t)atoi(argv[i]);
79               break;
80
81           case 'n' : /* -n nice-value */
82               i ++;
83               if (i >= argc)
84                 usage();
85
86               niceval = atoi(argv[i]);
87               break;
88
89           case 'u' : /* -g gid */
90               i ++;
91               if (i >= argc)
92                 usage();
93
94               uid = (uid_t)atoi(argv[i]);
95               break;
96
97           default :
98               fprintf(stderr, "cups-exec: Unknown option '-%c'.\n", *opt);
99               usage();
100         }
101       }
102     }
103     else
104       break;
105   }
106
107  /*
108   * Check that we have enough arguments...
109   */
110
111   if ((i + 3) > argc)
112   {
113     fputs("cups-exec: Insufficient arguments.\n", stderr);
114     usage();
115   }
116
117  /*
118   * Make sure side and back channel FDs are non-blocking...
119   */
120
121   fcntl(3, F_SETFL, O_NDELAY);
122   fcntl(4, F_SETFL, O_NDELAY);
123
124  /*
125   * Change UID, GID, and nice value...
126   */
127
128   if (uid)
129     nice(niceval);
130
131   if (!getuid())
132   {
133     if (setgid(gid))
134       exit(errno + 100);
135
136     if (setgroups(1, &gid))
137       exit(errno + 100);
138
139     if (uid && setuid(uid))
140       exit(errno + 100);
141   }
142
143   umask(077);
144
145 #ifdef HAVE_SANDBOX_H
146  /*
147   * Run in a separate security profile...
148   */
149
150   if (strcmp(argv[i], "none") &&
151       sandbox_init(argv[i], SANDBOX_NAMED_EXTERNAL, &sandbox_error))
152   {
153     cups_file_t *fp;                    /* File */
154     char        line[1024];             /* Line from file */
155     int         linenum = 0;            /* Line number in file */
156
157     fprintf(stderr, "DEBUG: sandbox_init failed: %s (%s)\n", sandbox_error,
158             strerror(errno));
159     sandbox_free_error(sandbox_error);
160
161     if ((fp = cupsFileOpen(argv[i], "r")) != NULL)
162     {
163       while (cupsFileGets(fp, line, sizeof(line)))
164       {
165         linenum ++;
166         fprintf(stderr, "DEBUG: %4d  %s\n", linenum, line);
167       }
168       cupsFileClose(fp);
169     }
170
171     return (100 + EINVAL);
172   }
173 #endif /* HAVE_SANDBOX_H */
174
175  /*
176   * Execute the program...
177   */
178
179   execv(argv[i + 1], argv + i + 2);
180
181  /*
182   * If we get here, execv() failed...
183   */
184
185   fprintf(stderr, "DEBUG: execv failed: %s\n", strerror(errno));
186   return (errno + 100);
187 }
188
189
190 /*
191  * 'usage()' - Show program usage.
192  */
193
194 static void
195 usage(void)
196 {
197   fputs("Usage: cups-exec [-g gid] [-n nice-value] [-u uid] /path/to/profile /path/to/program argv0 argv1 ... argvN\n", stderr);
198   exit(1);
199 }