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