/[path-sandbox]/trunk/sandbox_futils.c
Gentoo

Contents of /trunk/sandbox_futils.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 108 - (show annotations) (download) (as text)
Wed Jun 8 13:52:33 2005 UTC (9 years, 1 month ago) by azarah
File MIME type: text/x-csrc
File size: 13013 byte(s)
Do not abort if TMPDIR is not valid, but rather use '/tmp', bug #94360.  Also
make sure we re-export the new TMPDIR environment variable.

1 /*
2 * Copyright (C) 2002 Brad House <brad@mainstreetsoftworks.com>
3 * Distributed under the terms of the GNU General Public License, v2 or later
4 * Author: Brad House <brad@mainstreetsoftworks.com>
5 *
6 * $Header$
7 *
8 */
9
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <limits.h>
16 #include <string.h>
17 #include <stdarg.h>
18 #include <sys/file.h>
19 #include <sys/stat.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <sys/resource.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26
27 #include <grp.h>
28 #include <pwd.h>
29
30 #include "sandbox.h"
31 #include "config.h"
32
33 /* BEGIN Prototypes */
34 SB_STATIC int file_security_check(char *filename);
35 /* END Prototypes */
36
37 /* glibc modified getcwd() functions */
38 SB_STATIC char *egetcwd(char *, size_t);
39
40 SB_STATIC char *get_sandbox_path(char *argv0)
41 {
42 char path[SB_PATH_MAX];
43
44 memset(path, 0, sizeof(path));
45 /* ARGV[0] specifies full path */
46 if (argv0[0] == '/') {
47 strncpy(path, argv0, sizeof(path) - 1);
48
49 /* ARGV[0] specifies relative path */
50 } else {
51 if (-1 != readlink("/proc/self/exe", path, sizeof(path)))
52 path[sizeof(path) - 1] = '\0';
53 else
54 path[0] = '\0';
55 }
56
57 /* Return just directory */
58 return (sb_dirname(path));
59 }
60
61 SB_STATIC char *get_sandbox_lib(char *sb_path)
62 {
63 char path[SB_PATH_MAX];
64
65 #ifdef SB_HAVE_64BIT_ARCH
66 snprintf(path, sizeof(path), "%s", LIB_NAME);
67 #else
68 snprintf(path, sizeof(path), "%s/%s", LIBSANDBOX_PATH, LIB_NAME);
69 if (file_exist(path, 0) <= 0) {
70 snprintf(path, sizeof(path), "%s%s", sb_path, LIB_NAME);
71 }
72 #endif
73 return (strdup(path));
74 }
75
76 SB_STATIC char *get_sandbox_pids_file(const char *tmp_dir)
77 {
78 char path[SB_PATH_MAX];
79
80 if (0 < getenv("SANDBOX_PIDS_FILE")) {
81 return (strdup(getenv("SANDBOX_PIDS_FILE")));
82 }
83
84 snprintf(path, SB_PATH_MAX, "%s%s", tmp_dir, PIDS_FILE);
85 return (strdup(path));
86 }
87
88 SB_STATIC char *get_sandbox_rc(char *sb_path)
89 {
90 char path[SB_PATH_MAX];
91
92 snprintf(path, sizeof(path), "%s/%s", SANDBOX_BASHRC_PATH, BASHRC_NAME);
93 if (file_exist(path, 0) <= 0) {
94 snprintf(path, sizeof(path), "%s%s", sb_path, BASHRC_NAME);
95 }
96 return (strdup(path));
97 }
98
99 SB_STATIC char *get_sandbox_log(const char *tmp_dir)
100 {
101 char path[SB_PATH_MAX];
102 char *sandbox_log_env = NULL;
103
104 sandbox_log_env = getenv(ENV_SANDBOX_LOG);
105
106 /* THIS CHUNK BREAK THINGS BY DOING THIS:
107 * SANDBOX_LOG=/tmp/sandbox-app-admin/superadduser-1.0.7-11063.log
108 */
109 if ((NULL != sandbox_log_env) &&
110 (NULL != strchr(sandbox_log_env, '/')))
111 sandbox_log_env = NULL;
112
113 snprintf(path, sizeof(path) - 1, "%s%s%s%s%d%s",
114 tmp_dir, LOG_FILE_PREFIX,
115 (sandbox_log_env == NULL ? "" : sandbox_log_env),
116 (sandbox_log_env == NULL ? "" : "-"),
117 getpid(), LOG_FILE_EXT);
118 return (strdup(path));
119 }
120
121 SB_STATIC int get_tmp_dir(char *tmp_dir)
122 {
123 if (NULL == realpath(getenv(ENV_TMPDIR) ? getenv(ENV_TMPDIR)
124 : TMPDIR,
125 tmp_dir)) {
126 if (NULL == realpath(TMPDIR, tmp_dir))
127 return -1;
128 }
129
130 return 0;
131 }
132
133 SB_STATIC char *get_sandbox_debug_log(const char *tmp_dir)
134 {
135 char path[SB_PATH_MAX];
136 char *sandbox_debug_log_env = NULL;
137
138 sandbox_debug_log_env = getenv(ENV_SANDBOX_DEBUG_LOG);
139
140 /* THIS CHUNK BREAK THINGS BY DOING THIS:
141 * SANDBOX_DEBUG_LOG=/tmp/sandbox-app-admin/superadduser-1.0.7-11063.log
142 */
143 if ((NULL != sandbox_debug_log_env) &&
144 (NULL != strchr(sandbox_debug_log_env, '/')))
145 sandbox_debug_log_env = NULL;
146
147 snprintf(path, sizeof(path) - 1, "%s%s%s%s%d%s",
148 tmp_dir, DEBUG_LOG_FILE_PREFIX,
149 (sandbox_debug_log_env == NULL ? "" : sandbox_debug_log_env),
150 (sandbox_debug_log_env == NULL ? "" : "-"),
151 getpid(), LOG_FILE_EXT);
152 return (strdup(path));
153 }
154
155 /* Obtain base directory name. Do not allow trailing / */
156 SB_STATIC char *sb_dirname(const char *path)
157 {
158 char *ret = NULL;
159 char *ptr = NULL;
160 int loc = 0, i;
161 int cut_len = -1;
162
163 /* don't think NULL will ever be passed, but just in case */
164 if (NULL == path)
165 return (strdup("."));
166
167 /* Grab pointer to last slash */
168 ptr = strrchr(path, '/');
169 if (NULL == ptr) {
170 return (strdup("."));
171 }
172
173 /* decimal location of pointer */
174 loc = ptr - path;
175
176 /* Remove any trailing slash */
177 for (i = loc - 1; i >= 0; i--) {
178 if (path[i] != '/') {
179 cut_len = i + 1; /* make cut_len the length of the string to keep */
180 break;
181 }
182 }
183
184 /* It could have been just a plain /, return a 1byte 0 filled string */
185 if (-1 == cut_len)
186 return (strdup(""));
187
188 /* Allocate memory, and return the directory */
189 ret = (char *)malloc((cut_len + 1) * sizeof(char));
190 memcpy(ret, path, cut_len);
191 ret[cut_len] = 0;
192
193 return (ret);
194 }
195
196 /*
197 SB_STATIC char* dirname(const char* path)
198 {
199 char* base = NULL;
200 unsigned int length = 0;
201
202 base = strrchr(path, '/');
203 if (NULL == base)
204 {
205 return strdup(".");
206 }
207 while (base > path && *base == '/')
208 {
209 base--;
210 }
211 length = (unsigned int) 1 + base - path;
212
213 base = malloc(sizeof(char)*(length+1));
214 memmove(base, path, length);
215 base[length] = 0;
216
217 return base;
218 }*/
219
220 /* Convert text (string) modes to integer values */
221 SB_STATIC int file_getmode(char *mode)
222 {
223 int mde = 0;
224 if (0 == strcasecmp(mode, "r+")) {
225 mde = O_RDWR | O_CREAT;
226 } else if (0 == strcasecmp(mode, "w+")) {
227 mde = O_RDWR | O_CREAT | O_TRUNC;
228 } else if (0 == strcasecmp(mode, "a+")) {
229 mde = O_RDWR | O_CREAT | O_APPEND;
230 } else if (0 == strcasecmp(mode, "r")) {
231 mde = O_RDONLY;
232 } else if (0 == strcasecmp(mode, "w")) {
233 mde = O_WRONLY | O_CREAT | O_TRUNC;
234 } else if (0 == strcasecmp(mode, "a")) {
235 mde = O_WRONLY | O_APPEND | O_CREAT;
236 } else {
237 mde = O_RDONLY;
238 }
239 return (mde);
240 }
241
242 /* Get current position in file */
243 SB_STATIC long file_tell(int fp)
244 {
245 return (lseek(fp, 0L, SEEK_CUR));
246 }
247
248 /* lock the file, preferrably the POSIX way */
249 SB_STATIC int file_lock(int fd, int lock, char *filename)
250 {
251 int err;
252 #ifdef USE_FLOCK
253 if (flock(fd, lock) < 0) {
254 err = errno;
255 fprintf(stderr, ">>> %s flock file lock: %s\n", filename, strerror(err));
256 return 0;
257 }
258 #else
259 struct flock fl;
260 fl.l_type = lock;
261 fl.l_whence = SEEK_SET;
262 fl.l_start = 0L;
263 fl.l_len = 0L;
264 fl.l_pid = getpid();
265 if (fcntl(fd, F_SETLKW, &fl) < 0) {
266 err = errno;
267 fprintf(stderr, ">>> %s fcntl file lock: %s\n", filename, strerror(err));
268 return 0;
269 }
270 #endif
271 return 1;
272 }
273
274 /* unlock the file, preferrably the POSIX way */
275 SB_STATIC int file_unlock(int fd)
276 {
277 #ifdef USE_FLOCK
278 if (flock(fd, LOCK_UN) < 0) {
279 perror(">>> flock file unlock");
280 return 0;
281 }
282 #else
283 struct flock fl;
284 fl.l_type = F_UNLCK;
285 fl.l_whence = SEEK_SET;
286 fl.l_start = 0L;
287 fl.l_len = 0L;
288 fl.l_pid = getpid();
289 if (fcntl(fd, F_SETLKW, &fl) < 0) {
290 perror(">>> fcntl file unlock");
291 return 0;
292 }
293 #endif
294 return 1;
295 }
296
297 /* Auto-determine from how the file was opened, what kind of lock to lock
298 * the file with
299 */
300 SB_STATIC int file_locktype(char *mode)
301 {
302 #ifdef USE_FLOCK
303 if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+'))
304 || (NULL != strchr(mode, 'a')))
305 return (LOCK_EX);
306 return (LOCK_SH);
307 #else
308 if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+'))
309 || (NULL != strchr(mode, 'a')))
310 return (F_WRLCK);
311 return (F_RDLCK);
312 #endif
313 }
314
315 /* Use standard fopen style modes to open the specified file. Also auto-determines and
316 * locks the file either in shared or exclusive mode depending on opening mode
317 */
318 SB_STATIC int file_open(char *filename, char *mode, int perm_specified, ...)
319 {
320 int fd;
321 char error[SB_BUF_LEN];
322 va_list ap;
323 int perm;
324 char *group = NULL;
325 struct group *group_struct;
326
327 file_security_check(filename);
328
329 if (perm_specified) {
330 va_start(ap, perm_specified);
331 perm = va_arg(ap, int);
332 group = va_arg(ap, char *);
333 va_end(ap);
334 }
335 fd = open(filename, file_getmode(mode));
336 file_security_check(filename);
337 if (-1 == fd) {
338 snprintf(error, sizeof(error), ">>> %s file mode: %s open", filename, mode);
339 perror(error);
340 return (fd);
341 }
342 if (perm_specified) {
343 if (fchmod(fd, 0664) && (0 == getuid())) {
344 snprintf(error, sizeof(error), ">>> Could not set mode: %s", filename);
345 perror(error);
346 }
347 }
348 if (NULL != group) {
349 group_struct = getgrnam(group);
350 if (NULL == group_struct) {
351 snprintf(error, sizeof(error), ">>> Could not get grp number: %s", group);
352 perror(error);
353 } else {
354 if (fchown(fd, -1, group_struct->gr_gid) && (0 == getuid())) {
355 snprintf(error, sizeof(error), ">>> Could not set group: %s", filename);
356 perror(error);
357 }
358 }
359 }
360 /* Only lock the file if opening succeeded */
361 if (-1 != fd) {
362 if (file_security_check(filename) != 0) {
363 /* Security violation occured between the last check and the */
364 /* creation of the file. As SpanKY pointed out there is a race */
365 /* condition here, so if there is a problem here we'll mesg and */
366 /* bail out to avoid it until we can work and test a better fix. */
367 fprintf(stderr, "\n\nSECURITY RACE CONDITION: Problem recurred after creation!\nBAILING OUT\n\n");
368 exit(127);
369 }
370
371 if (0 == file_lock(fd, file_locktype(mode), filename)) {
372 close(fd);
373 return -1;
374 }
375 } else {
376 snprintf(error, sizeof(error), ">>> %s file mode:%s open", filename, mode);
377 perror(error);
378 }
379 return (fd);
380 }
381
382 /* Close and unlock file */
383 SB_STATIC void file_close(int fd)
384 {
385 if (-1 != fd) {
386 file_unlock(fd);
387 close(fd);
388 }
389 }
390
391 /* Return length of file */
392 SB_STATIC long file_length(int fd)
393 {
394 long pos, len;
395 pos = file_tell(fd);
396 len = lseek(fd, 0L, SEEK_END);
397 lseek(fd, pos, SEEK_SET);
398 return (len);
399 }
400
401 /* Zero out file */
402 SB_STATIC int file_truncate(int fd)
403 {
404 lseek(fd, 0L, SEEK_SET);
405 if (ftruncate(fd, 0) < 0) {
406 perror(">>> file truncate");
407 return 0;
408 }
409 return 1;
410 }
411
412 /* Check to see if a file exists Return: 1 success, 0 file not found, -1 error */
413 SB_STATIC int file_exist(char *filename, int checkmode)
414 {
415 struct stat mystat;
416
417 /* Verify file exists and is regular file (not sym link) */
418 if (checkmode) {
419 if (-1 == lstat(filename, &mystat)) {
420 /* file doesn't exist */
421 if (ENOENT == errno) {
422 return 0;
423 } else { /* permission denied or other error */
424 perror(">>> stat file");
425 return -1;
426 }
427 }
428 if (!S_ISREG(mystat.st_mode))
429 return -1;
430
431 /* Just plain verify the file exists */
432 } else {
433 if (-1 == stat(filename, &mystat)) {
434 /* file does not exist */
435 if (ENOENT == errno) {
436 return 0;
437 } else { /* permission denied or other error */
438 perror(">>> stat file");
439 return -1;
440 }
441 }
442 }
443
444 return 1;
445 }
446
447 SB_STATIC int file_security_check(char *filename)
448 { /* 0 == fine, >0 == problem */
449 struct stat stat_buf;
450 struct group *group_buf;
451 struct passwd *passwd_buf;
452
453 passwd_buf = getpwnam("portage");
454 group_buf = getgrnam("portage");
455
456 if ((lstat(filename, &stat_buf) == -1) && (errno == ENOENT)) {
457 /* Doesn't exist. */
458 return 0;
459 } else {
460 if ((stat_buf.st_nlink) > 1) { /* Security: We are handlinked... */
461 if (unlink(filename)) {
462 fprintf(stderr, "Unable to delete file in security violation (hardlinked): %s\n", filename);
463 exit(127);
464 }
465 fprintf(stderr, "File in security violation (hardlinked): %s\n", filename);
466 return 1;
467 } else if (S_ISLNK(stat_buf.st_mode)) { /* Security: We are a symlink? */
468 fprintf(stderr, "File in security violation (symlink): %s\n", filename);
469 exit(127);
470 } else if (0 == S_ISREG(stat_buf.st_mode)) { /* Security: special file */
471 fprintf(stderr, "File in security violation (not regular): %s\n", filename);
472 exit(127);
473 } else if (stat_buf.st_mode & S_IWOTH) { /* Security: We are o+w? */
474 if (unlink(filename)) {
475 fprintf(stderr, "Unable to delete file in security violation (world write): %s\n", filename);
476 exit(127);
477 }
478 fprintf(stderr, "File in security violation (world write): %s\n", filename);
479 return 1;
480 } else
481 if (!((stat_buf.st_uid == 0) || (stat_buf.st_uid == getuid()) ||
482 ((passwd_buf != NULL) && (stat_buf.st_uid == passwd_buf->pw_uid))) ||
483 !((stat_buf.st_gid == 0) || (stat_buf.st_gid == getgid()) ||
484 ((group_buf != NULL) && (stat_buf.st_gid == group_buf->gr_gid)))) {
485 /* Security: Owner/Group isn't right. */
486
487 /* uid = 0 or myuid or portage */
488 /* gid = 0 or mygid or portage */
489
490 if (0) {
491 fprintf(stderr, "--1: %d,%d,%d,%d\n--2: %d,%d,%d,%d\n",
492 (stat_buf.st_uid == 0),
493 (stat_buf.st_uid == getuid()),
494 (passwd_buf != NULL),
495 (passwd_buf != NULL) ? (stat_buf.st_uid == passwd_buf->pw_uid) : -1,
496 (stat_buf.st_gid == 0),
497 (stat_buf.st_gid == getgid()),
498 (group_buf != NULL),
499 (group_buf != NULL) ? (stat_buf.st_gid == group_buf->gr_gid) : -1);
500 }
501
502 /* manpage: "The return value may point to static area" */
503 /* DO NOT ACTUALLY FREE THIS... It'll segfault. */
504 /* if(passwd_buf != NULL) { free(passwd_buf); } */
505 /* if(group_buf != NULL) { free(group_buf); } */
506
507 if (unlink(filename)) {
508 fprintf(stderr, "Unable to delete file in security violation (bad owner/group): %s\n", filename);
509 exit(127);
510 }
511 fprintf(stderr, "File in security violation (bad owner/group): %s\n", filename);
512 return 1;
513 }
514 } /* Stat */
515 return 0;
516 }
517
518 // vim:noexpandtab noai:cindent ai

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.20