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

Contents of /trunk/sandbox_futils.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 13 - (show annotations) (download) (as text)
Sat Nov 20 13:05:24 2004 UTC (10 years, 1 month ago) by ferringb
File MIME type: text/x-csrc
File size: 11756 byte(s)
removed the /usr/lib/portage/ hardcoded reference for bashrc.

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