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

Diff of /trunk/sandbox_futils.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.138  
changed lines
  Added in v.139

  ViewVC Help
Powered by ViewVC 1.1.20