]>
Commit | Line | Data |
---|---|---|
0268488e | 1 | /* |
c82f05ea | 2 | * Sandbox helper for CUPS. |
0268488e | 3 | * |
c82f05ea | 4 | * Copyright 2007-2014 by Apple Inc. |
0268488e | 5 | * |
c82f05ea MS |
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/". | |
0268488e MS |
11 | * |
12 | * Usage: | |
13 | * | |
7131e285 | 14 | * cups-exec /path/to/profile [-u UID] [-g GID] [-n NICE] /path/to/program argv0 argv1 ... argvN |
0268488e MS |
15 | */ |
16 | ||
17 | /* | |
18 | * Include necessary headers... | |
19 | */ | |
20 | ||
21 | #include <cups/string-private.h> | |
8fe0183a | 22 | #include <cups/file.h> |
0268488e | 23 | #include <unistd.h> |
c82f05ea | 24 | #include <fcntl.h> |
07623986 | 25 | #include <grp.h> |
c82f05ea | 26 | #include <sys/stat.h> |
0268488e | 27 | #ifdef HAVE_SANDBOX_H |
0268488e | 28 | # include <sandbox.h> |
a4845881 MS |
29 | # ifndef SANDBOX_NAMED_EXTERNAL |
30 | # define SANDBOX_NAMED_EXTERNAL 0x0003 | |
31 | # endif /* !SANDBOX_NAMED_EXTERNAL */ | |
6961465f | 32 | # pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
0268488e MS |
33 | #endif /* HAVE_SANDBOX_H */ |
34 | ||
35 | ||
28c194b0 MS |
36 | /* |
37 | * Local functions... | |
38 | */ | |
39 | ||
40 | static void usage(void) __attribute__((noreturn)); | |
41 | ||
42 | ||
0268488e MS |
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 | { | |
28c194b0 MS |
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 */ | |
0268488e | 56 | #ifdef HAVE_SANDBOX_H |
28c194b0 | 57 | char *sandbox_error = NULL; /* Sandbox error, if any */ |
0268488e MS |
58 | #endif /* HAVE_SANDBOX_H */ |
59 | ||
60 | ||
28c194b0 MS |
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 | ||
0268488e MS |
107 | /* |
108 | * Check that we have enough arguments... | |
109 | */ | |
110 | ||
28c194b0 | 111 | if ((i + 3) > argc) |
0268488e | 112 | { |
28c194b0 MS |
113 | fputs("cups-exec: Insufficient arguments.\n", stderr); |
114 | usage(); | |
0268488e MS |
115 | } |
116 | ||
c82f05ea MS |
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 | ||
c82f05ea MS |
124 | /* |
125 | * Change UID, GID, and nice value... | |
126 | */ | |
127 | ||
c82f05ea MS |
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 | ||
8fe0183a | 145 | #ifdef HAVE_SANDBOX_H |
0268488e | 146 | /* |
8fe0183a | 147 | * Run in a separate security profile... |
0268488e MS |
148 | */ |
149 | ||
28c194b0 MS |
150 | if (strcmp(argv[i], "none") && |
151 | sandbox_init(argv[i], SANDBOX_NAMED_EXTERNAL, &sandbox_error)) | |
8fe0183a MS |
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 | ||
28c194b0 | 161 | if ((fp = cupsFileOpen(argv[i], "r")) != NULL) |
8fe0183a MS |
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 */ | |
0268488e | 174 | |
28c194b0 MS |
175 | /* |
176 | * Execute the program... | |
177 | */ | |
178 | ||
179 | execv(argv[i + 1], argv + i + 2); | |
180 | ||
0268488e MS |
181 | /* |
182 | * If we get here, execv() failed... | |
183 | */ | |
184 | ||
185 | fprintf(stderr, "DEBUG: execv failed: %s\n", strerror(errno)); | |
8fe0183a | 186 | return (errno + 100); |
0268488e MS |
187 | } |
188 | ||
189 | ||
28c194b0 MS |
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 | } |