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

Contents of /trunk/sandbox_futils.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 97 - (show annotations) (download) (as text)
Fri May 13 12:52:10 2005 UTC (13 years, 5 months ago) by azarah
File MIME type: text/x-csrc
File size: 12630 byte(s)
Add get_sandbox_debug_log(), and use it (add behaviour similar to SANDBOX_LOG
if already exported when sandbox started).  Fix get_sandbox_log() and new
get_sandbox_debug_log() to not use already exported environment variables if
they have '/' in them.  Use snprintf()'s instead of strncpy()'s.  More
SB_PATH_MAX fixes.

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