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

Contents of /trunk/sandbox_futils.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations) (download) (as text)
Fri Nov 19 22:03:42 2004 UTC (9 years, 11 months ago) by ferringb
File MIME type: text/x-csrc
File size: 11733 byte(s)
Initial revision

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

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.20