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

Contents of /trunk/sandbox_futils.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (show annotations) (download) (as text)
Sat Apr 23 20:44:15 2005 UTC (9 years, 8 months ago) by azarah
File MIME type: text/x-csrc
File size: 11855 byte(s)
Make sure all functions used in libsandbox.c is declared static.  Define
SB_STATIC in localdecls.h for this.  Include sandbox_futils.c rather than
linking with its object.  Hopefully this will fix bug #90153.

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