You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
780 lines
24 KiB
780 lines
24 KiB
/* |
|
* Soapbox - A way to deny processes to write files outside some directories |
|
* |
|
* Copyright (C) 2003 by Dag Wieers <dag@wieers.com> |
|
* Copyright (C) 2012 by Ralf S. Engelschall <rse@engelschall.com> |
|
* |
|
* This program is free software; you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation; either version 2 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program is distributed in the hope that it will be useful, |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
* GNU General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program; if not, write to the Free Software |
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
*/ |
|
|
|
#define _GNU_SOURCE |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <stdarg.h> |
|
#include <string.h> |
|
#include <errno.h> |
|
#include <dlfcn.h> |
|
#include <unistd.h> |
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
#include <utime.h> |
|
#include <fcntl.h> |
|
#include <limits.h> |
|
#include <time.h> |
|
#ifdef __FreeBSD__ |
|
#include <libgen.h> |
|
#endif |
|
|
|
/* |
|
* ==== GLOBAL VARIABLES ==== |
|
*/ |
|
|
|
static int (*sb_real_chmod) (const char *, mode_t); |
|
static int (*sb_real_chown) (const char *, uid_t, gid_t); |
|
static int (*sb_real_lchown) (const char *, uid_t, gid_t); |
|
static int (*sb_real_link) (const char *, const char *); |
|
static int (*sb_real_mkdir) (const char *, mode_t); |
|
static int (*sb_real_mkfifo) (const char *, mode_t); |
|
static int (*sb_real_mknod) (const char *, mode_t, dev_t); |
|
static int (*sb_real___xmknod)(int, const char *, mode_t, dev_t *); |
|
static int (*sb_real_open) (const char *, int, ...); |
|
static int (*sb_real_open64) (const char *, int, ...); |
|
static int (*sb_real_creat) (const char *, mode_t); |
|
static int (*sb_real_creat64) (const char *, mode_t); |
|
static int (*sb_real_remove) (const char *); |
|
static int (*sb_real_rename) (const char *, const char *); |
|
static int (*sb_real_rmdir) (const char *); |
|
static int (*sb_real_symlink) (const char *, const char *); |
|
static int (*sb_real_unlink) (const char *); |
|
static int (*sb_real_utime) (const char *, const struct utimbuf *); |
|
static int (*sb_real_utimes) (const char *, const struct timeval *); |
|
|
|
#define SB_PATHSEP ":,;|" |
|
|
|
enum { SB_R_FILE, SB_R_LINK }; |
|
|
|
enum { SB_A_UNKN, SB_A_WARN, SB_A_ERR, SB_A_HALT }; |
|
#define SB_A_DEFAULT SB_A_WARN |
|
#define SB_A_DEFAULT_NAME "warn" |
|
|
|
static char *sb_path; |
|
static int sb_devnull; |
|
static int sb_action = SB_A_UNKN; |
|
static int sb_debug = 0; |
|
static FILE *sb_logfp; |
|
|
|
/* |
|
* ==== UTILITY FUNCTIONS ==== |
|
*/ |
|
|
|
static void sb_die(FILE *out, const char *str, ...) { |
|
va_list argptr; |
|
|
|
fprintf(out, "soapbox: "); |
|
va_start(argptr, str); |
|
vfprintf(out, str, argptr); |
|
va_end(argptr); |
|
fprintf(out, "\n"); |
|
exit(-1); |
|
} |
|
|
|
static void sb_log(int level, const char *str, ...) { |
|
va_list argptr; |
|
|
|
if (sb_debug & level || level == 0) { |
|
if (level != 0) |
|
fprintf(sb_logfp, "soapbox: debug%i: ", level); |
|
else |
|
fprintf(sb_logfp, "soapbox: "); |
|
va_start(argptr, str); |
|
vfprintf(sb_logfp, str, argptr); |
|
va_end(argptr); |
|
fprintf(sb_logfp, "\n"); |
|
} |
|
} |
|
|
|
static void sb_dlcheck(const char *err) { |
|
if (err != NULL) |
|
sb_die(sb_logfp, "%s", err); |
|
} |
|
|
|
/* |
|
* ==== DSO MANAGEMENT ==== |
|
*/ |
|
|
|
/* DSO initialization */ |
|
void _init(int argc, char *argv[]) { |
|
char *soapboxaction; |
|
char *soapboxdbg; |
|
char *soapboxlog; |
|
|
|
/* make output unbuffered */ |
|
setvbuf(stdout, (char *)NULL, _IONBF, 0); |
|
setvbuf(stderr, (char *)NULL, _IONBF, 0); |
|
|
|
/* handle and unset logging environment variable */ |
|
soapboxlog = getenv("SOAPBOXLOG"); |
|
unsetenv("SOAPBOXLOG"); |
|
if (soapboxlog == NULL || *soapboxlog == '\0') { |
|
sb_logfp = stderr; |
|
} |
|
else { |
|
sb_logfp = fopen(soapboxlog, "a"); |
|
if (sb_logfp == NULL) { |
|
sb_logfp = stderr; |
|
sb_die(sb_logfp, "%s: %s (%i)", soapboxlog, strerror(errno), errno); |
|
} |
|
setvbuf(sb_logfp, (char *)NULL, _IONBF, 0); |
|
} |
|
|
|
/* handle and unset debugging environment variable */ |
|
soapboxdbg = getenv("SOAPBOXDEBUG"); |
|
unsetenv("SOAPBOXDEBUG"); |
|
if (soapboxdbg != NULL) |
|
sb_debug = atoi(soapboxdbg); |
|
sb_log(8, "Variable SOAPBOXDEBUG is set to %i.", sb_debug); |
|
|
|
/* handle and unset path environment variable */ |
|
sb_path = getenv("SOAPBOXPATH"); |
|
unsetenv("SOAPBOXPATH"); |
|
if (sb_path == NULL) |
|
sb_path = ""; |
|
if (sb_path == NULL || *sb_path=='\0') |
|
sb_log(8, "Variable SOAPBOXPATH is not set. Not allowed to write anywhere."); |
|
else |
|
sb_log(8, "Variable SOAPBOXPATH is set to \"%s\".", sb_path); |
|
|
|
/* handle and unset action environment variable */ |
|
soapboxaction = getenv("SOAPBOXACTION"); |
|
unsetenv("SOAPBOXACTION"); |
|
if (soapboxaction == NULL || *soapboxaction == '\0') { |
|
soapboxaction = SB_A_DEFAULT_NAME; |
|
sb_log(8, "Variable SOAPBOXACTION is not set. Using \"%s\" by default.", SB_A_DEFAULT_NAME); |
|
} |
|
else |
|
sb_log(8, "Variable SOAPBOXACTION is set to \"%s\".", soapboxaction); |
|
if (strcmp(soapboxaction, "warn") == 0) |
|
sb_action = SB_A_WARN; |
|
else if (strcmp(soapboxaction, "err") == 0) |
|
sb_action = SB_A_ERR; |
|
else if (strcmp(soapboxaction, "halt") == 0) |
|
sb_action = SB_A_HALT; |
|
if (sb_action == SB_A_UNKN) { |
|
sb_log(8, "Variable SOAPBOXACTION=\"%s\" is unknown. Using \"%s\" by default.", soapboxaction, SB_A_DEFAULT_NAME); |
|
sb_action = SB_A_DEFAULT; |
|
} |
|
|
|
/* resolve real functions from libc */ |
|
sb_real_chmod = dlsym(RTLD_NEXT, "chmod"); sb_dlcheck(dlerror()); |
|
sb_real_chown = dlsym(RTLD_NEXT, "chown"); sb_dlcheck(dlerror()); |
|
sb_real_lchown = dlsym(RTLD_NEXT, "lchown"); sb_dlcheck(dlerror()); |
|
sb_real_link = dlsym(RTLD_NEXT, "link"); sb_dlcheck(dlerror()); |
|
sb_real_mkdir = dlsym(RTLD_NEXT, "mkdir"); sb_dlcheck(dlerror()); |
|
sb_real_mkfifo = dlsym(RTLD_NEXT, "mkfifo"); sb_dlcheck(dlerror()); |
|
sb_real_mknod = dlsym(RTLD_NEXT, "mknod"); sb_dlcheck(dlerror()); |
|
#ifdef __linux__ |
|
sb_real___xmknod = dlsym(RTLD_NEXT, "__xmknod"); sb_dlcheck(dlerror()); |
|
#endif |
|
sb_real_open = dlsym(RTLD_NEXT, "open"); sb_dlcheck(dlerror()); |
|
#ifdef __linux__ |
|
sb_real_open64 = dlsym(RTLD_NEXT, "open64"); sb_dlcheck(dlerror()); |
|
#endif |
|
sb_real_creat = dlsym(RTLD_NEXT, "creat"); sb_dlcheck(dlerror()); |
|
#ifdef __linux__ |
|
sb_real_creat64 = dlsym(RTLD_NEXT, "creat64"); sb_dlcheck(dlerror()); |
|
#endif |
|
sb_real_remove = dlsym(RTLD_NEXT, "remove"); sb_dlcheck(dlerror()); |
|
sb_real_rename = dlsym(RTLD_NEXT, "rename"); sb_dlcheck(dlerror()); |
|
sb_real_rmdir = dlsym(RTLD_NEXT, "rmdir"); sb_dlcheck(dlerror()); |
|
sb_real_symlink = dlsym(RTLD_NEXT, "symlink"); sb_dlcheck(dlerror()); |
|
sb_real_unlink = dlsym(RTLD_NEXT, "unlink"); sb_dlcheck(dlerror()); |
|
sb_real_utime = dlsym(RTLD_NEXT, "utime"); sb_dlcheck(dlerror()); |
|
sb_real_utimes = dlsym(RTLD_NEXT, "utimes"); sb_dlcheck(dlerror()); |
|
|
|
/* open /dev/null for reuse */ |
|
sb_devnull = sb_real_open("/dev/null", O_RDWR); |
|
if (sb_devnull == -1) |
|
sb_die(sb_logfp, "/dev/null: %s", strerror(errno)); |
|
} |
|
|
|
/* DSO finish */ |
|
void _fini(void) { |
|
close(sb_devnull); |
|
if (sb_logfp != stderr) |
|
fclose(sb_logfp); |
|
} |
|
|
|
/* |
|
* ==== HELPER FUNCTIONS ==== |
|
*/ |
|
|
|
static char *sb_dirname(const char *path) { |
|
char *ptr; |
|
char safe[PATH_MAX+1]; |
|
safe[0]='\0'; safe[PATH_MAX]='\0'; |
|
|
|
if (strrchr(path, '/') == NULL) |
|
getcwd(safe, PATH_MAX); |
|
else { |
|
snprintf(safe, PATH_MAX, "%s", path); |
|
ptr = strrchr(safe, '/'); |
|
*ptr = '\0'; |
|
} |
|
return strndup(safe, strlen(safe)); |
|
} |
|
|
|
/* sb_rewrite relative path to absolute. */ |
|
static char *sb_rewrite(const char *path, const int flag) { |
|
char *linkdir, *out; |
|
struct stat *buf; |
|
char safe[PATH_MAX+1]; |
|
|
|
/* terminate string for safety */ |
|
safe[0] = '\0'; |
|
safe[PATH_MAX] = '\0'; |
|
|
|
/* to make sure path is not empty and defined. Return empty string */ |
|
if (path == NULL || *path == '\0') |
|
return strndup(safe, 0); |
|
|
|
/* check if file exists */ |
|
buf = malloc(sizeof(struct stat)); |
|
if (lstat(path, buf) == 0) { |
|
/* case 1: file exists */ |
|
int type = (buf->st_mode & 0170000); |
|
int mode = (buf->st_mode & 07777); |
|
if (sb_debug & 8) { |
|
switch (type) { |
|
case S_IFLNK: sb_log(8, "File \"%s\" is a symlink. (%04o)", path, mode); break;; |
|
case S_IFREG: sb_log(8, "File \"%s\" is a regular file. (%04o)", path, mode); break;; |
|
case S_IFDIR: sb_log(8, "File \"%s\" is a directory. (%04o)", path, mode); break;; |
|
case S_IFCHR: sb_log(8, "File \"%s\" is a character device. (%04o)", path, mode); break;; |
|
case S_IFBLK: sb_log(8, "File \"%s\" is a block device. (%04o)", path, mode); break;; |
|
default: sb_log(8, "File \"%s\" is an unknown file type. (%04o)", path, mode); break;; |
|
} |
|
} |
|
|
|
/* resolve path */ |
|
if ((type == S_IFLNK) && (flag == SB_R_LINK)) { |
|
/* if it is a symlink and if asked (SB_R_LINK), we should make its |
|
dirname absolute (not the symlink) and add its basename */ |
|
linkdir = sb_rewrite(sb_dirname(path), SB_R_LINK); |
|
snprintf(safe, PATH_MAX, "%s/%s", linkdir, basename(path)); |
|
free(linkdir); |
|
} |
|
else |
|
realpath(path, safe); |
|
} |
|
else { |
|
/* case 2: file not existing */ |
|
sb_log(8, "File \"%s\" does not exist.", path); |
|
realpath(path, safe); /* TODO: realpath(3) resolves not correctly for not existing path?! */ |
|
} |
|
free(buf); |
|
out = strndup(safe, strlen(safe)); |
|
if (strcmp(path, out) != 0) |
|
sb_log(4, "File \"%s\" is actually \"%s\".", path, out); |
|
return out; |
|
} |
|
|
|
/* verify if program has access to a path. */ |
|
static int sb_has_access(char *path) { |
|
int found = 0; |
|
char *pathlist; |
|
char *curpath; |
|
|
|
pathlist = strndup(sb_path, strlen(sb_path)); |
|
curpath = strtok(pathlist, SB_PATHSEP); |
|
while (curpath != NULL && !found) { |
|
if (curpath != '\0' && strstr(path, curpath) == path) { |
|
found = 1; |
|
sb_log(4, "Allow access to \"%s\" (in \"%s\").", path, curpath); |
|
} |
|
curpath = strtok(NULL, SB_PATHSEP); |
|
} |
|
free(pathlist); |
|
return found; |
|
} |
|
|
|
static void sb_str_cmode(char *str, const char *cmode) { |
|
char *temp; |
|
|
|
temp = strndup(str, strlen(str)); |
|
if (strlen(str) != 0) |
|
snprintf(str, PATH_MAX, "%s|%s", temp, cmode); |
|
else |
|
snprintf(str, PATH_MAX, "%s%s", temp, cmode); |
|
free(temp); |
|
} |
|
|
|
static char *sb_str_flags(const int flags) { |
|
char str[PATH_MAX+1]; |
|
|
|
/* terminate string for safety */ |
|
str[0] = '\0'; |
|
str[PATH_MAX] = '\0'; |
|
|
|
if (flags & O_WRONLY) sb_str_cmode(str, "O_WRONLY"); |
|
else if (flags & O_RDWR) sb_str_cmode(str, "O_RDWR"); |
|
else sb_str_cmode(str, "O_RDONLY"); |
|
|
|
if (flags & O_EXCL) sb_str_cmode(str, "O_EXCL"); |
|
if (flags & O_TRUNC) sb_str_cmode(str, "O_TRUNC"); |
|
if (flags & O_APPEND) sb_str_cmode(str, "O_APPEND"); |
|
if (flags & O_NONBLOCK) sb_str_cmode(str, "O_NONBLOCK"); |
|
if (flags & O_CREAT) sb_str_cmode(str, "O_CREAT"); |
|
if (flags & O_NOCTTY) sb_str_cmode(str, "O_NOCTTY"); |
|
if (flags & O_SYNC) sb_str_cmode(str, "O_SYNC"); |
|
if (flags & O_NOFOLLOW) sb_str_cmode(str, "O_NOFOLLOW"); |
|
if (flags & O_DIRECT) sb_str_cmode(str, "O_DIRECT"); |
|
if (flags & O_ASYNC) sb_str_cmode(str, "O_ASYNC"); |
|
#ifdef O_LARGEFILE |
|
if (flags & O_LARGEFILE) sb_str_cmode(str, "O_LARGEFILE"); |
|
#endif |
|
if (flags & O_DIRECTORY) sb_str_cmode(str, "O_DIRECTORY"); |
|
|
|
return strndup(str, strlen(str)); |
|
} |
|
|
|
static char *str_timet(time_t time) { |
|
struct tm *t; |
|
char str[PATH_MAX+1]; |
|
|
|
t = localtime(&time); |
|
str[0] = '\0'; |
|
str[PATH_MAX] = '\0'; |
|
sprintf(str, "%04i/%02i/%02i-%02i:%02i:%02i", |
|
t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); |
|
free(t); |
|
return strndup(str, strlen(str)); |
|
} |
|
|
|
static char *str_utimbuf(const struct utimbuf *buf) { |
|
char str[PATH_MAX+1]; |
|
|
|
str[0] = '\0'; |
|
str[PATH_MAX] = '\0'; |
|
if (buf == NULL) |
|
sprintf(str, "NULL"); |
|
else |
|
sprintf(str, "[%s, %s]", str_timet(buf->actime), str_timet(buf->modtime)); |
|
return strndup(str, strlen(str)); |
|
} |
|
|
|
/* |
|
* ==== OVERLOADED LIBC FUNCTIONS ==== |
|
*/ |
|
|
|
int chmod(const char *path, mode_t mode) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start chmod(\"%s\", %04o).", path, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do chmod(\"%s\", %04o).", path, mode); |
|
return sb_real_chmod(path, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to chmod(\"%s\", %04o).", rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int chown(const char *path, uid_t owner, gid_t group) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start chown(\"%s\", %i, %i).", path, owner, group); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do chown(\"%s\", %i, %i).", path, owner, group); |
|
return sb_real_chown(path, owner, group); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to chown(\"%s\", %i, %i).", rpath, owner, group); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int lchown(const char *path, uid_t owner, gid_t group) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start lchown(\"%s\", %i, %i).", path, owner, group); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do lchown(\"%s\", %i, %i).", path, owner, group); |
|
return sb_real_lchown(path, owner, group); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to lchown(\"%s\", %i, %i).", rpath, owner, group); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int link(const char *oldpath, const char *newpath) { |
|
char *oldrpath, *newrpath; |
|
|
|
sb_log(2, "Start link(\"%s\", \"%s\").", oldpath, newpath); |
|
oldrpath = sb_rewrite(oldpath, SB_R_FILE); |
|
newrpath = sb_rewrite(newpath, SB_R_FILE); |
|
if (sb_has_access(oldrpath) && sb_has_access(newrpath)) { |
|
sb_log(4, "Do link(\"%s\", \"%s\").", oldpath, newpath); |
|
return sb_real_link(oldpath, newpath); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to link(\"%s\", \"%s\").", oldrpath, newrpath); |
|
free(oldrpath); |
|
free(newrpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int mkdir(const char *path, mode_t mode) { |
|
char *rpath; |
|
sb_log(2, "Start mkdir(\"%s\", %04o).", path, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do mkdir(\"%s\", %04o).", path, mode); |
|
return sb_real_mkdir(path, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to mkdir(\"%s\", %04o).", rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int mkfifo(const char *path, mode_t mode) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start mkfifo(\"%s\", %04o).", path, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do mkfifo(\"%s\", %04o).", path, mode); |
|
return sb_real_mkfifo(path, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to mkfifo(\"%s\", %04o).", rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int mknod(const char *path, mode_t mode, dev_t dev) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start mknod(\"%s\", %04o).", path, mode); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do mknod(\"%s\", %04o).", path, mode); |
|
return sb_real_mknod(path, mode, dev); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to mknod(\"%s\", %04o).", rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start __xmknod(%i, \"%s\", %04o).", ver, path, mode); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do __xmknod(%i, \"%s\", %04o).", ver, path, mode); |
|
return sb_real___xmknod(ver, path, mode, dev); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to __xmknod(%i, \"%s\", %04o).", ver, rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int open(const char *path, int flags, ...) { |
|
char *rpath; |
|
char *strflags; |
|
va_list argptr; |
|
mode_t mode; |
|
int found; |
|
|
|
strflags = sb_str_flags(flags); |
|
if (flags & O_CREAT) { |
|
va_start(argptr, flags); |
|
mode = (mode_t)va_arg(argptr, int); |
|
va_end(argptr); |
|
} |
|
else |
|
mode = 0; |
|
sb_log(2, "Start open(\"%s\", %s, %04o).", path, strflags, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if ((found = sb_has_access(rpath)) || !(flags & (O_WRONLY|O_RDWR))) { |
|
/* disable O_CREAT when O_RDONLY */ |
|
if (!found) { |
|
flags &= ~O_CREAT; |
|
strflags = sb_str_flags(flags); |
|
} |
|
sb_log(4, "Do open(\"%s\", %s, %04o).", path, strflags, mode); |
|
return sb_real_open(path, flags, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to open(\"%s\", %s, %04o).", rpath, strflags, mode); |
|
free(rpath); |
|
free(strflags); |
|
if (sb_action == SB_A_WARN) |
|
return sb_devnull; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int open64(const char *path, int flags, ...) { |
|
char *rpath; |
|
char *strflags; |
|
va_list argptr; |
|
mode_t mode; |
|
int found; |
|
|
|
strflags=sb_str_flags(flags); |
|
if (flags & O_CREAT) { |
|
va_start(argptr, flags); |
|
mode = (mode_t)va_arg(argptr, int); |
|
va_end(argptr); |
|
} |
|
else |
|
mode = 0; |
|
sb_log(2, "Start open64(\"%s\", %s, %04o).", path, strflags, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if ((found = sb_has_access(rpath)) || !(flags & (O_WRONLY|O_RDWR))) { |
|
/* disable O_CREAT when O_RDONLY */ |
|
if (!found) { |
|
flags &= ~O_CREAT; |
|
strflags = sb_str_flags(flags); |
|
} |
|
sb_log(4, "Do open64(\"%s\", %s, %04o).", path, strflags, mode); |
|
return sb_real_open64(path, flags, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to open64(\"%s\", %s, %04o).", rpath, strflags, mode); |
|
free(rpath); |
|
free(strflags); |
|
if (sb_action == SB_A_WARN) |
|
return sb_devnull; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int creat(const char *path, mode_t mode) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start creat(\"%s\", %04o).", path, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do creat(\"%s\", %04o).", path, mode); |
|
return sb_real_creat(path, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to creat(\"%s\", %04o).", rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return sb_devnull; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int creat64(const char *path, mode_t mode) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start creat64(\"%s\", %04o).", path, mode); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do creat64(\"%s\", %04o).", path, mode); |
|
return sb_real_creat64(path, mode); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to creat64(\"%s\", %04o).", rpath, mode); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return sb_devnull; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int remove(const char *path) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start remove(\"%s\").", path); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do remove(\"%s\").", path); |
|
return sb_real_remove(path); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to remove(\"%s\").", rpath); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int rename(const char *oldpath, const char *newpath) { |
|
char *oldrpath, *newrpath; |
|
|
|
sb_log(2, "Start rename(\"%s\", \"%s\").", oldpath, newpath); |
|
oldrpath = sb_rewrite(oldpath, SB_R_LINK); |
|
newrpath = sb_rewrite(newpath, SB_R_FILE); |
|
if (sb_has_access(oldrpath) && sb_has_access(newrpath)) { |
|
sb_log(4, "Do rename(\"%s\", \"%s\").", oldpath, newpath); |
|
return sb_real_rename(oldpath, newpath); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to rename(\"%s\", \"%s\").", oldrpath, newrpath); |
|
free(oldrpath); |
|
free(newrpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int rmdir(const char *path) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start rmdir(\"%s\").", path); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do rmdir(\"%s\").", path); |
|
return sb_real_rmdir(path); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to rmdir(\"%s\").", rpath); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int symlink(const char *oldpath, const char *newpath) { |
|
char *newrpath; |
|
|
|
sb_log(2, "Start symlink(\"%s\", \"%s\").", oldpath, newpath); |
|
newrpath = sb_rewrite(newpath, SB_R_LINK); |
|
if (sb_has_access(newrpath)) { |
|
sb_log(4, "Do symlink(\"%s\", \"%s\").", oldpath, newpath); |
|
return sb_real_symlink(oldpath, newpath); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to symlink(\"%s\", \"%s\").", oldpath, newrpath); |
|
free(newrpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int unlink(const char *path) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start unlink(\"%s\").", path); |
|
rpath = sb_rewrite(path, SB_R_LINK); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do unlink(\"%s\").", path); |
|
return sb_real_unlink(path); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to unlink(\"%s\").", rpath); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int utime(const char *path, const struct utimbuf *buf) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start utime(\"%s\", NULL).", path); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do utime(\"%s\", NULL).", path); |
|
return sb_real_utime(path, buf); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to utime(\"%s\", %s).", rpath, str_utimbuf(buf)); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
int utimes(const char *path, const struct timeval *tvp) { |
|
char *rpath; |
|
|
|
sb_log(2, "Start utimes(\"%s\", NULL).", path); |
|
rpath = sb_rewrite(path, SB_R_FILE); |
|
if (sb_has_access(rpath)) { |
|
sb_log(4, "Do utimes(\"%s\", NULL).", path); |
|
return sb_real_utimes(path, tvp); |
|
} |
|
if (sb_action == SB_A_HALT) |
|
exit(0); |
|
sb_log(1, "Attempt to utimes(\"%s\", NULL).", rpath); |
|
free(rpath); |
|
if (sb_action == SB_A_WARN) |
|
return 0; |
|
errno = EACCES; |
|
return -1; |
|
} |
|
|
|
|