diff options
Diffstat (limited to 'guts')
67 files changed, 1755 insertions, 0 deletions
diff --git a/guts/COPYRIGHT b/guts/COPYRIGHT new file mode 100644 index 0000000..c96e1b1 --- /dev/null +++ b/guts/COPYRIGHT @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2010 Wind River Systems, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the Lesser GNU General Public License version 2.1 as + * published by the Free Software Foundation. + * + * 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 Lesser GNU General Public License for more details. + * + * You should have received a copy of the Lesser GNU General Public License + * version 2.1 along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ diff --git a/guts/README b/guts/README new file mode 100644 index 0000000..be00d30 --- /dev/null +++ b/guts/README @@ -0,0 +1,109 @@ +The files in this directory are partially machine-generated, and are +all covered by the COPYRIGHT file in this directory. + +The set of functions covered here may seem surprising. For instance, +obviously, fopen(3) simply calls the underlying open(2) syscall. But... +There is a problem. In a few places in glibc, the syscalls are inlined +such that there is no actual call to the C function open(2), just a raw +call. So there are a couple of functions (fopen, freopen) which are +wrapped with intent only to detect the possible creation of files. + +Many of these functions are closely related. Some programs may have +calls to openat(), while others have calls to __openat_2(). To reduce +code duplication, a number of functions are implemented purely as calls +to other functions. + +When a *at() function exists, the regular function is implemented +as *at() with AT_FDCWD as the directory fd (see the dummy #define of +this in pseudo_client.h, used for systems which lack these.) On systems +where AT_NOFOLLOW_SYMLINKS is not defined, the underlying *at() functions +don't exist, so we provide a bare implementation which works only when +the fd is AT_FDCWD... + +The creat64 and open64 families are equivalent to the plain versions with +O_LARGEFILE in mode bits. (Again, there's a suitable dummy #define +in pseudo_client.h.) By contrast, the stat64 functions actually do have +some difference -- the structure they manipulate is not the same. + +The following table shows which functions are merely wrappers around +other functions: + + chmod: fchmodat + chown: fchownat + creat64: openat + creat: openat + __fxstatat: __fxstatat64 + __fxstat: __fxstat64 + __lxstat64: __fxstatat64 + __lxstat: __fxstatat + mkdir: mkdirat + open64: openat + __openat_2: openat + __openat64_2: openat + openat64: openat + open: openat + rename: renameat + symlink: symlinkat + unlink: unlinkat + __xmknod: __xmknodat + __xstat64: __fxstatat64 + __xstat: __fxstatat + +The following functions are full implementations: + + chdir + fchdir + fchmod + fchmodat + fchown + fchownat + __fxstat64 + __fxstatat64 + lchown + mkdirat + openat + renameat + rmdir + symlinkat + unlinkat + __xmknodat + +The following functions provide only partial implementations, to trap special +cases, to track internal data structures (for instance, close() is tracked so +that the path to a file descriptor can be dropped when the file descriptor +is closed), or to handle functions which may not use the underlying syscall +wrappers: + + close + dup + dup2 + fclose + fopen + fopen64 + freopen + mkstemp + fcntl + fork + link + vfork + +The following functions don't have any direct database interactions, +but are used to simulate the permissions system: + + getegid + getuid + setgid + setreuid + geteuid + setegid + setgroups + setuid + getgid + seteuid + setregid + getresgid + setfsgid + setresgid + getresuid + setfsuid + setresuid diff --git a/guts/__fxstat.c b/guts/__fxstat.c new file mode 100644 index 0000000..e715f6c --- /dev/null +++ b/guts/__fxstat.c @@ -0,0 +1,17 @@ +/* + * int + * wrap___fxstat(int ver, int fd, struct stat *buf) { + * int rc = -1; + */ + + struct stat64 buf64; + /* populate buffer with complete data */ + real___fxstat(ver, fd, buf); + /* obtain fake data */ + rc = wrap___fxstat64(ver, fd, &buf64); + /* overwrite */ + pseudo_stat32_from64(buf, &buf64); + +/* return rc; + * } + */ diff --git a/guts/__fxstat64.c b/guts/__fxstat64.c new file mode 100644 index 0000000..59f8a59 --- /dev/null +++ b/guts/__fxstat64.c @@ -0,0 +1,28 @@ +/* + * int + * wrap___fxstat64(int ver, int fd, struct stat64 *buf) { + * int rc = -1; + */ + pseudo_msg_t *msg; + int save_errno; + + rc = real___fxstat64(ver, fd, buf); + save_errno = errno; + if (rc == -1) { + return rc; + } + if (ver != _STAT_VER) { + pseudo_debug(1, "version mismatch: got stat version %d, only supporting %d\n", ver, _STAT_VER); + errno = save_errno; + return rc; + } + msg = pseudo_client_op(OP_FSTAT, 0, fd, -1, 0, buf); + if (msg) { + if (msg->result == RESULT_SUCCEED) + pseudo_stat_msg(buf, msg); + } + + errno = save_errno; +/* return rc; + * } + */ diff --git a/guts/__fxstatat.c b/guts/__fxstatat.c new file mode 100644 index 0000000..4bc2454 --- /dev/null +++ b/guts/__fxstatat.c @@ -0,0 +1,29 @@ +/* + * static int + * wrap___fxstatat(int ver, int dirfd, const char *path, struct stat *buf, int flags) { + * int rc = -1; + */ + + struct stat64 buf64; + /* populate buffer with complete data */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (flags & AT_SYMLINK_NOFOLLOW) { + rc = real___lxstat(ver, path, buf); + } else { + rc = real___xstat(ver, path, buf); + } +#else + real___fxstatat(ver, dirfd, path, buf, flags); +#endif + /* obtain fake data */ + rc = wrap___fxstatat64(ver, dirfd, path, &buf64, flags); + /* overwrite */ + pseudo_stat32_from64(buf, &buf64); + +/* return rc; + * } + */ diff --git a/guts/__fxstatat64.c b/guts/__fxstatat64.c new file mode 100644 index 0000000..3edd8c7 --- /dev/null +++ b/guts/__fxstatat64.c @@ -0,0 +1,71 @@ +/* + * static int + * wrap___fxstatat64(int ver, int dirfd, const char *path, struct stat64 *buf, int flags) { + * int rc = -1; + */ + pseudo_msg_t *msg; + int save_errno; + mode_t save_mode = 0; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } +#endif + /* If the file is actually a symlink, we grab the db values + * for the underlying target, then mask in the size and mode + * from the link. Otherwise, we just use the db values (if + * any). + */ + if (flags & AT_SYMLINK_NOFOLLOW) { +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___lxstat64(ver, path, buf); +#else + rc = real___fxstatat64(ver, dirfd, path, buf, flags); +#endif + if (rc == -1) { + return rc; + } + /* it's a symlink, stash its mode */ + if (S_ISLNK(buf->st_mode)) { + save_mode = buf->st_mode; + } + } else { +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___xstat64(ver, path, buf); +#else + rc = real___fxstatat64(ver, dirfd, path, buf, flags); +#endif + if (rc == -1) { + return rc; + } + } + /* if we got here: we have valid stat data, for either the symlink + * (if it is a symlink, and we have NOFOLLOW on) or the target. + */ + save_errno = errno; + + if (ver != _STAT_VER) { + pseudo_debug(1, "version mismatch: got stat version %d, only supporting %d\n", ver, _STAT_VER); + errno = save_errno; + return rc; + } + + /* query database + * note that symlink canonicalizing is now automatic, so we + * don't need to check for a symlink on this end + */ + msg = pseudo_client_op(OP_STAT, flags, -1, dirfd, path, buf); + if (msg) { + pseudo_stat_msg(buf, msg); + if (save_mode) { + buf->st_mode = save_mode; + } + } + + errno = save_errno; + +/* return rc; + * } + */ diff --git a/guts/__lxstat.c b/guts/__lxstat.c new file mode 100644 index 0000000..4678f28 --- /dev/null +++ b/guts/__lxstat.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap___lxstat(int ver, const char *path, struct stat *buf) { + * int rc = -1; + */ + + rc = wrap___fxstatat(ver, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); + +/* + * } + */ diff --git a/guts/__lxstat64.c b/guts/__lxstat64.c new file mode 100644 index 0000000..36ac18b --- /dev/null +++ b/guts/__lxstat64.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap___lxstat64(int ver, const char *path, struct stat64 *buf) { + * int rc = -1; + */ + + rc = wrap___fxstatat64(ver, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); + +/* + * } + */ diff --git a/guts/__openat64_2.c b/guts/__openat64_2.c new file mode 100644 index 0000000..85b950b --- /dev/null +++ b/guts/__openat64_2.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap___openat64_2(int dirfd, const char *path, int flags) { + * int rc = -1; + */ + + rc = wrap_openat(dirfd, path, flags, O_LARGEFILE); + +/* return rc; + * } + */ diff --git a/guts/__openat_2.c b/guts/__openat_2.c new file mode 100644 index 0000000..ef8d7ad --- /dev/null +++ b/guts/__openat_2.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap___openat_2(int dirfd, const char *path, int flags) { + * int rc = -1; + */ + + rc = wrap_openat(dirfd, path, flags, 0); + +/* return rc; + * } + */ diff --git a/guts/__xmknod.c b/guts/__xmknod.c new file mode 100644 index 0000000..5fb395d --- /dev/null +++ b/guts/__xmknod.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap___xmknod(int ver, const char *path, mode_t mode, dev_t *dev) { + * int rc = -1; + */ + + rc = wrap___xmknodat(ver, AT_FDCWD, path, mode, dev); + +/* return rc; + * } + */ diff --git a/guts/__xmknodat.c b/guts/__xmknodat.c new file mode 100644 index 0000000..a86d6aa --- /dev/null +++ b/guts/__xmknodat.c @@ -0,0 +1,68 @@ +/* + * static int + * wrap___xmknodat(int ver, int dirfd, const char *path, mode_t mode, dev_t *dev) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = real___xstat64(_STAT_VER, path, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc != -1) { + /* if we can stat the file, you can't mknod it */ + errno = EEXIST; + return -1; + } + if (!dev) { + errno = EINVAL; + return -1; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_open(path, O_CREAT | O_WRONLY | O_EXCL, PSEUDO_FS_MODE(mode)); +#else + rc = real_openat(dirfd, path, O_CREAT | O_WRONLY | O_EXCL, + PSEUDO_FS_MODE(mode)); +#endif + if (rc == -1) + return -1; + real___fxstat64(_STAT_VER, rc, &buf); + /* mknod does not really open the file. We don't have + * to use wrap_close because we've never exposed this file + * descriptor to the client code. + */ + real_close(rc); + + /* mask in the mode type bits again */ + buf.st_mode = (PSEUDO_DB_MODE(buf.st_mode, mode) & 07777) | + (mode & ~07777); + buf.st_rdev = *dev; + msg = pseudo_client_op(OP_MKNOD, AT_SYMLINK_NOFOLLOW, -1, dirfd, path, &buf); + if (!msg) { + errno = ENOSYS; + rc = -1; + } else if (msg->result != RESULT_SUCCEED) { + errno = msg->xerrno; + rc = -1; + } else { + rc = 0; + } + if (rc == -1) { + int save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + real_unlink(path); +#else + real_unlinkat(dirfd, path, AT_SYMLINK_NOFOLLOW); +#endif + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/guts/__xstat.c b/guts/__xstat.c new file mode 100644 index 0000000..ef2e363 --- /dev/null +++ b/guts/__xstat.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap___xstat(int ver, const char *path, struct stat *buf) { + * int rc = -1; + */ + + rc = wrap___fxstatat(ver, AT_FDCWD, path, buf, 0); + +/* return rc; + * } + */ diff --git a/guts/__xstat64.c b/guts/__xstat64.c new file mode 100644 index 0000000..f02358b --- /dev/null +++ b/guts/__xstat64.c @@ -0,0 +1,10 @@ +/* + * static int + * wrap___xstat64(int ver, const char *path, struct stat64 *buf) { + * int rc = -1; + */ + rc = wrap___fxstatat64(ver, AT_FDCWD, path, buf, 0); + +/* return rc; + * } + */ diff --git a/guts/chdir.c b/guts/chdir.c new file mode 100644 index 0000000..b910060 --- /dev/null +++ b/guts/chdir.c @@ -0,0 +1,15 @@ +/* + * static int + * wrap_chdir(const char *path) { + * int rc = -1; + */ + pseudo_debug(3, "chdir: %s\n", path ? path : "<nil>"); + rc = real_chdir(path); + + if (rc != -1) { + pseudo_client_op(OP_CHDIR, 0, -1, -1, path, 0); + } + +/* return rc; + * } + */ diff --git a/guts/chmod.c b/guts/chmod.c new file mode 100644 index 0000000..2d5de91 --- /dev/null +++ b/guts/chmod.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_chmod(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_fchmodat(AT_FDCWD, path, mode, 0); + +/* return rc; + * } + */ diff --git a/guts/chown.c b/guts/chown.c new file mode 100644 index 0000000..0a82989 --- /dev/null +++ b/guts/chown.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_chown(const char *path, uid_t owner, gid_t group) { + * int rc = -1; + */ + + rc = wrap_fchownat(AT_FDCWD, path, owner, group, 0); + +/* return rc; + * } + */ diff --git a/guts/close.c b/guts/close.c new file mode 100644 index 0000000..8edbee9 --- /dev/null +++ b/guts/close.c @@ -0,0 +1,14 @@ +/* + * static int + * wrap_close(int fd) { + * int rc = -1; + */ + /* this cleans up an internal table, and shouldn't even + * make it to the server. + */ + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); + rc = real_close(fd); + +/* return rc; + * } + */ diff --git a/guts/creat.c b/guts/creat.c new file mode 100644 index 0000000..e4c0b60 --- /dev/null +++ b/guts/creat.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_creat(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(AT_FDCWD, path, O_CREAT|O_WRONLY|O_TRUNC, mode); + +/* return rc; + * } + */ diff --git a/guts/creat64.c b/guts/creat64.c new file mode 100644 index 0000000..655c166 --- /dev/null +++ b/guts/creat64.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_creat64(const char *path, ...mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(AT_FDCWD, path, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE, mode); + +/* return rc; + * } + */ diff --git a/guts/dup.c b/guts/dup.c new file mode 100644 index 0000000..941a5d9 --- /dev/null +++ b/guts/dup.c @@ -0,0 +1,16 @@ +/* + * static int + * wrap_dup(int fd) { + * int rc = -1; + */ + int save_errno; + + rc = real_dup(fd); + save_errno = errno; + pseudo_debug(2, "dup: %d->%d\n", fd, rc); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); + + errno = save_errno; +/* return rc; + * } + */ diff --git a/guts/dup2.c b/guts/dup2.c new file mode 100644 index 0000000..360c3ad --- /dev/null +++ b/guts/dup2.c @@ -0,0 +1,19 @@ +/* + * static int + * wrap_dup2(int oldfd, int newfd) { + * int rc = -1; + */ + int save_errno; + + /* close existing one first - this also causes the socket to the + * server to get moved around if someone tries to overwrite it. */ + pseudo_debug(2, "dup2: %d->%d\n", oldfd, newfd); + pseudo_client_op(OP_CLOSE, 0, newfd, -1, 0, 0); + rc = real_dup2(oldfd, newfd); + save_errno = errno; + pseudo_client_op(OP_DUP, 0, oldfd, newfd, 0, 0); + errno = save_errno; + +/* return rc; + * } + */ diff --git a/guts/fchdir.c b/guts/fchdir.c new file mode 100644 index 0000000..5289f4c --- /dev/null +++ b/guts/fchdir.c @@ -0,0 +1,15 @@ +/* + * static int + * wrap_fchdir(int dirfd) { + * int rc = -1; + */ + + rc = real_fchdir(dirfd); + + if (rc != -1) { + pseudo_client_op(OP_CHDIR, 0, -1, dirfd, 0, 0); + } + +/* return rc; + * } + */ diff --git a/guts/fchmod.c b/guts/fchmod.c new file mode 100644 index 0000000..df2f9e9 --- /dev/null +++ b/guts/fchmod.c @@ -0,0 +1,30 @@ +/* + * static int + * wrap_fchmod(int fd, mode_t mode) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + int save_errno = errno; + + if (real___fxstat64(_STAT_VER, fd, &buf) == -1) { + /* can't stat it, can't chmod it */ + return -1; + } + buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777); + msg = pseudo_client_op(OP_FCHMOD, 0, fd, -1, 0, &buf); + real_fchmod(fd, PSEUDO_FS_MODE(mode)); + if (!msg) { + errno = ENOSYS; + rc = -1; + } else if (msg->result != RESULT_SUCCEED) { + errno = msg->xerrno; + rc = -1; + } else { + errno = save_errno; + rc = 0; + } + +/* return rc; + * } + */ diff --git a/guts/fchmodat.c b/guts/fchmodat.c new file mode 100644 index 0000000..36bd4d1 --- /dev/null +++ b/guts/fchmodat.c @@ -0,0 +1,70 @@ +/* + * static int + * wrap_fchmodat(int dirfd, const char *path, mode_t mode, int flags) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + int save_errno; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (flags & AT_SYMLINK_NOFOLLOW) { + rc = real___lxstat64(_STAT_VER, path, &buf); + } else { + rc = real___xstat64(_STAT_VER, path, &buf); + } +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, flags); +#endif + if (rc == -1) { + return rc; + } + if (S_ISLNK(buf.st_mode)) { + /* we don't really support chmod of a symlink */ + errno = ENOSYS; + return -1; + } + save_errno = errno; + + /* purely for debugging purposes: check whether file + * is already in database. + */ + msg = pseudo_client_op(OP_STAT, flags, -1, -1, path, &buf); + if (!msg || msg->result != RESULT_SUCCEED) { + pseudo_debug(2, "chmodat to 0%o on %d/%s, ino %llu, new file.\n", + mode, dirfd, path, (unsigned long long) buf.st_ino); + + } + + /* user bits added so "root" can always access files. */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + /* note: if path was a symlink, and AT_NOFOLLOW_SYMLINKS was + * specified, we already bailed previously. */ + real_chmod(path, PSEUDO_FS_MODE(mode)); +#else + real_fchmodat(dirfd, path, PSEUDO_FS_MODE(mode), flags); +#endif + /* we ignore a failure from underlying fchmod, because pseudo + * may believe you are permitted to change modes that the filesystem + * doesn't. + */ + + buf.st_mode = (buf.st_mode & ~07777) | (mode & 07777); + msg = pseudo_client_op(OP_CHMOD, flags, -1, dirfd, path, &buf); + if (!msg) { + errno = ENOSYS; + rc = -1; + } else if (msg->result != RESULT_SUCCEED) { + errno = msg->xerrno; + rc = -1; + } else { + rc = 0; + } + +/* return rc; + * } + */ diff --git a/guts/fchown.c b/guts/fchown.c new file mode 100644 index 0000000..4d420c8 --- /dev/null +++ b/guts/fchown.c @@ -0,0 +1,54 @@ +/* + * static int + * wrap_fchown(int fd, uid_t owner, gid_t group) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + int save_errno; + + if (real___fxstat64(_STAT_VER, fd, &buf) == -1) { + save_errno = errno; + pseudo_debug(2, "fchown failing because fxstat failed: %s\n", + strerror(errno)); + errno = save_errno; + return -1; + } + if (owner == -1 || group == -1) { + msg = pseudo_client_op(OP_STAT, 0, fd, -1, NULL, &buf); + /* copy in any existing values... */ + if (msg) { + if (msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } else { + pseudo_debug(2, "fchown fd %d, ino %llu, unknown file.\n", + fd, (unsigned long long) buf.st_ino); + } + } else { + pseudo_diag("stat within chown of fd %d [%llu] failed.\n", + fd, (unsigned long long) buf.st_ino); + } + } + /* now override with arguments */ + if (owner != -1) { + buf.st_uid = owner; + } + if (group != -1) { + buf.st_gid = group; + } + pseudo_debug(2, "fchown, fd %d: %d:%d -> %d:%d\n", + fd, owner, group, buf.st_uid, buf.st_gid); + msg = pseudo_client_op(OP_FCHOWN, 0, fd, -1, 0, &buf); + if (!msg) { + errno = ENOSYS; + rc = -1; + } else if (msg->result != RESULT_SUCCEED) { + errno = msg->xerrno; + rc = -1; + } else { + rc = 0; + } + +/* return rc; + * } + */ diff --git a/guts/fchownat.c b/guts/fchownat.c new file mode 100644 index 0000000..8d24d3e --- /dev/null +++ b/guts/fchownat.c @@ -0,0 +1,64 @@ +/* + * static int + * wrap_fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + int save_errno; + int doing_link = 0; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (flags & AT_SYMLINK_NOFOLLOW) { + rc = real___lxstat64(_STAT_VER, path, &buf); + } else { + rc = real___xstat64(_STAT_VER, path, &buf); + } +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, flags); +#endif + if (rc == -1) { + return rc; + } + /* pseudo won't track the ownership, here */ + if (S_ISLNK(buf.st_mode)) { + doing_link = 1; + } + save_errno = errno; + + msg = pseudo_client_op(OP_STAT, flags, -1, -1, path, &buf); + /* copy in any existing values... */ + if (msg) { + if (msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } else { + pseudo_debug(2, "chownat to %d:%d on %d/%s, ino %llu, new file.\n", + owner, group, dirfd, path, + (unsigned long long) buf.st_ino); + } + } + /* now override with arguments */ + if (owner != -1) { + buf.st_uid = owner; + } + if (group != -1) { + buf.st_gid = group; + } + msg = pseudo_client_op(OP_CHOWN, flags, -1, dirfd, path, &buf); + if (!msg) { + errno = ENOSYS; + rc = -1; + } else if (msg->result != RESULT_SUCCEED) { + errno = msg->xerrno; + rc = -1; + } else { + rc = 0; + } + +/* return rc; + * } + */ diff --git a/guts/fclose.c b/guts/fclose.c new file mode 100644 index 0000000..e0c5681 --- /dev/null +++ b/guts/fclose.c @@ -0,0 +1,17 @@ +/* + * static int + * wrap_fclose(FILE *fp) { + * int rc = -1; + */ + + if (!fp) { + errno = EFAULT; + return -1; + } + int fd = fileno(fp); + pseudo_client_op(OP_CLOSE, 0, fd, -1, 0, 0); + rc = real_fclose(fp); + +/* return rc; + * } + */ diff --git a/guts/fcntl.c b/guts/fcntl.c new file mode 100644 index 0000000..d03d40c --- /dev/null +++ b/guts/fcntl.c @@ -0,0 +1,68 @@ +/* + * static int + * wrap_fcntl(int fd, int cmd, ...struct flock *lock) { + * int rc = -1; + */ + long arg; + int save_errno; + + /* we don't know whether we need lock or arg; grab both, which + * should be safe enough on Linuxy systems. */ + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + + switch (cmd) { + case F_DUPFD: +#ifdef F_DUPFD_CLOEXEC + case F_DUPFD_CLOEXEC: +#endif + /* actually do something */ + rc = real_fcntl(fd, cmd, arg); + save_errno = errno; + if (rc != -1) { + pseudo_debug(2, "fcntl_dup: %d->%d\n", fd, rc); + pseudo_client_op(OP_DUP, 0, fd, rc, 0, 0); + } + errno = save_errno; + break; + /* no argument: */ + case F_GETFD: + case F_GETFL: + case F_GETOWN: + case F_GETSIG: + case F_GETLEASE: + rc = real_fcntl(fd, cmd); + break; + /* long argument */ + case F_SETFD: + case F_SETFL: + case F_SETOWN: + case F_SETSIG: + case F_SETLEASE: + case F_NOTIFY: + rc = real_fcntl(fd, cmd, arg); + break; + /* struct flock * argument */ + case F_GETLK: + case F_SETLK: + case F_SETLKW: + rc = real_fcntl(fd, cmd, lock); + break; +#if defined(F_GETLK64) && (F_GETLK64 != F_GETLK) + /* the cast is safe, all struct pointers must smell the same */ + case F_GETLK64: + case F_SETLK64: + case F_SETLKW64: + rc = real_fcntl(fd, cmd, (struct flock64 *) lock); + break; +#endif + default: + pseudo_diag("unknown fcntl argument %d, assuming long argument.\n", + cmd); + rc = real_fcntl(fd, cmd, arg); + break; + } +/* return rc; + * } + */ diff --git a/guts/fopen.c b/guts/fopen.c new file mode 100644 index 0000000..2aae54c --- /dev/null +++ b/guts/fopen.c @@ -0,0 +1,32 @@ +/* + * static FILE * + * wrap_fopen(const char *path, const char *mode) { + * FILE * rc = 0; + */ + struct stat64 buf; + int save_errno; + int existed = (real___xstat64(_STAT_VER, path, &buf) != -1); + + rc = real_fopen(path, mode); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(2, "fopen '%s': fd %d\n", path, fd); + if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { + if (!existed) { + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, 0, fd, -1, path, &buf); + } else { + pseudo_debug(1, "fopen (fd %d) succeeded, but fstat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, 0, fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/guts/fopen64.c b/guts/fopen64.c new file mode 100644 index 0000000..0b0ab58 --- /dev/null +++ b/guts/fopen64.c @@ -0,0 +1,32 @@ +/* + * static FILE * + * wrap_fopen64(const char *path, const char *mode) { + * FILE * rc = 0; + */ + struct stat64 buf; + int save_errno; + int existed = (real___xstat64(_STAT_VER, path, &buf) != -1); + + rc = real_fopen64(path, mode); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(2, "fopen64 '%s': fd %d\n", path, fd); + if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { + if (!existed) { + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, 0, fd, -1, path, &buf); + } else { + pseudo_debug(1, "fopen64 (fd %d) succeeded, but fstat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, 0, fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/guts/fork.c b/guts/fork.c new file mode 100644 index 0000000..a49694f --- /dev/null +++ b/guts/fork.c @@ -0,0 +1,13 @@ +/* + * static int + * wrap_fork(void) { + * int rc = -1; + */ + + rc = real_fork(); + if (rc == 0) + pseudo_client_reset(); + +/* return rc; + * } + */ diff --git a/guts/freopen.c b/guts/freopen.c new file mode 100644 index 0000000..312bc0a --- /dev/null +++ b/guts/freopen.c @@ -0,0 +1,32 @@ +/* + * static FILE * + * wrap_freopen(const char *path, const char *mode, FILE *stream) { + * FILE * rc = NULL; + */ + struct stat64 buf; + int save_errno; + int existed = (real___xstat64(_STAT_VER, path, &buf) != -1); + + rc = real_freopen(path, mode, stream); + save_errno = errno; + + if (rc) { + int fd = fileno(rc); + + pseudo_debug(2, "freopen '%s': fd %d\n", path, fd); + if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { + if (!existed) { + pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); + } + pseudo_client_op(OP_OPEN, 0, fd, -1, path, &buf); + } else { + pseudo_debug(1, "fopen (fd %d) succeeded, but stat failed (%s).\n", + fd, strerror(errno)); + pseudo_client_op(OP_OPEN, 0, fd, -1, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/guts/getegid.c b/guts/getegid.c new file mode 100644 index 0000000..4a3c929 --- /dev/null +++ b/guts/getegid.c @@ -0,0 +1,11 @@ +/* + * static gid_t + * wrap_getegid(void) { + * gid_t rc = 0; + */ + + rc = pseudo_egid; + +/* return rc; + * } + */ diff --git a/guts/geteuid.c b/guts/geteuid.c new file mode 100644 index 0000000..508cc83 --- /dev/null +++ b/guts/geteuid.c @@ -0,0 +1,11 @@ +/* + * static uid_t + * wrap_geteuid(void) { + * uid_t rc = 0; + */ + + rc = pseudo_euid; + +/* return rc; + * } + */ diff --git a/guts/getgid.c b/guts/getgid.c new file mode 100644 index 0000000..415e3f0 --- /dev/null +++ b/guts/getgid.c @@ -0,0 +1,11 @@ +/* + * static gid_t + * wrap_getgid(void) { + * gid_t rc = 0; + */ + + rc = pseudo_rgid; + +/* return rc; + * } + */ diff --git a/guts/getresgid.c b/guts/getresgid.c new file mode 100644 index 0000000..3eb4fac --- /dev/null +++ b/guts/getresgid.c @@ -0,0 +1,20 @@ +/* + * static int + * wrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) { + * int rc = -1; + */ + if (rgid) + *rgid = pseudo_rgid; + if (egid) + *egid = pseudo_egid; + if (sgid) + *sgid = pseudo_sgid; + if (rgid && egid && sgid) { + rc = 0; + } else { + rc = -1; + errno = EFAULT; + } +/* return rc; + * } + */ diff --git a/guts/getresuid.c b/guts/getresuid.c new file mode 100644 index 0000000..2976f78 --- /dev/null +++ b/guts/getresuid.c @@ -0,0 +1,20 @@ +/* + * static int + * wrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) { + * int rc = -1; + */ + if (ruid) + *ruid = pseudo_ruid; + if (euid) + *euid = pseudo_euid; + if (suid) + *suid = pseudo_suid; + if (ruid && euid && suid) { + rc = 0; + } else { + rc = -1; + errno = EFAULT; + } +/* return rc; + * } + */ diff --git a/guts/getuid.c b/guts/getuid.c new file mode 100644 index 0000000..48294e2 --- /dev/null +++ b/guts/getuid.c @@ -0,0 +1,11 @@ +/* + * static uid_t + * wrap_getuid(void) { + * uid_t rc = 0; + */ + + rc = pseudo_ruid; + +/* return rc; + * } + */ diff --git a/guts/lchown.c b/guts/lchown.c new file mode 100644 index 0000000..6f7e53a --- /dev/null +++ b/guts/lchown.c @@ -0,0 +1,48 @@ +/* + * static int + * wrap_lchown(const char *path, uid_t owner, gid_t group) { + */ + pseudo_msg_t *msg; + struct stat64 buf; + + pseudo_debug(2, "lchown(%s, %d, %d)\n", + path ? path : "<null>", owner, group); + if (real___lxstat64(_STAT_VER, path, &buf) == -1) { + return -1; + } + if (owner == -1 || group == -1) { + msg = pseudo_client_op(OP_STAT, AT_SYMLINK_NOFOLLOW, -1, -1, path, &buf); + /* copy in any existing values... */ + if (msg) { + if (msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&buf, msg); + } else { + pseudo_debug(2, "lchown to %d:%d on %s, ino %llu, new file.\n", + owner, group, path, + (unsigned long long) buf.st_ino); + } + } else { + pseudo_diag("stat within lchown of '%s' [%llu] failed.\n", + path, (unsigned long long) buf.st_ino); + } + } + if (owner != -1) { + buf.st_uid = owner; + } + if (group != -1) { + buf.st_gid = group; + } + msg = pseudo_client_op(OP_CHOWN, AT_SYMLINK_NOFOLLOW, -1, -1, path, &buf); + if (!msg) { + errno = ENOSYS; + rc = -1; + } else if (msg->result != RESULT_SUCCEED) { + errno = msg->xerrno; + rc = -1; + } else { + rc = 0; + } + +/* return rc; + * } + */ diff --git a/guts/link.c b/guts/link.c new file mode 100644 index 0000000..278edd7 --- /dev/null +++ b/guts/link.c @@ -0,0 +1,29 @@ +/* + * static int + * wrap_link(const char *oldpath, const char *newpath) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 buf; + + rc = real_link(oldpath, newpath); + if (rc == 0) { + /* link(2) will not overwrite; if it succeeded, we know + * that there was no previous file with this name, so we + * shove it into the database. + */ + real___xstat64(_STAT_VER, oldpath, &buf); + /* a link should copy the existing database entry, if + * there is one. OP_LINK is also used to insert unseen + * files, though, so it can't be implicit. + */ + msg = pseudo_client_op(OP_STAT, 0, -1, -1, oldpath, &buf); + if (msg) { + pseudo_stat_msg(&buf, msg); + } + pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &buf); + } + +/* return rc; + * } + */ diff --git a/guts/mkdir.c b/guts/mkdir.c new file mode 100644 index 0000000..3177e4f --- /dev/null +++ b/guts/mkdir.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_mkdir(const char *path, mode_t mode) { + * int rc = -1; + */ + + rc = wrap_mkdirat(AT_FDCWD, path, mode); + +/* return rc; + * } + */ diff --git a/guts/mkdirat.c b/guts/mkdirat.c new file mode 100644 index 0000000..a5ae5d8 --- /dev/null +++ b/guts/mkdirat.c @@ -0,0 +1,34 @@ +/* + * static int + * wrap_mkdirat(int dirfd, const char *path, mode_t mode) { + * int rc = -1; + */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = real_mkdir(path, PSEUDO_FS_MODE(mode)); +#else + rc = real_mkdirat(dirfd, path, PSEUDO_FS_MODE(mode)); +#endif + if (rc != -1) { + struct stat64 buf; + int stat_rc; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + stat_rc = real___lxstat64(_STAT_VER, path, &buf); +#else + stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (stat_rc != -1) { + pseudo_client_op(OP_MKDIR, AT_SYMLINK_NOFOLLOW, -1, dirfd, path, &buf); + } else { + pseudo_debug(1, "mkdir of %s succeeded, but stat failed: %s\n", + path, strerror(errno)); + } + } + +/* return rc; + * } + */ diff --git a/guts/mkstemp.c b/guts/mkstemp.c new file mode 100644 index 0000000..b339b5c --- /dev/null +++ b/guts/mkstemp.c @@ -0,0 +1,25 @@ +/* + * static int + * wrap_mkstemp(char *template) { + * int rc = -1; + */ + struct stat64 buf; + int save_errno; + + rc = real_mkstemp(template); + + if (rc != -1) { + save_errno = errno; + if (real___fxstat64(_STAT_VER, rc, &buf) != -1) { + pseudo_client_op(OP_CREAT, 0, -1, -1, template, &buf); + pseudo_client_op(OP_OPEN, 0, rc, -1, template, &buf); + } else { + pseudo_debug(1, "mkstemp (fd %d) succeeded, but fstat failed (%s).\n", + rc, strerror(errno)); + pseudo_client_op(OP_OPEN, 0, rc, -1, template, 0); + } + errno = save_errno; + } +/* return rc; + * } + */ diff --git a/guts/open.c b/guts/open.c new file mode 100644 index 0000000..7348daf --- /dev/null +++ b/guts/open.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_open(const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + + return wrap_openat(AT_FDCWD, path, flags, mode); + +/* return rc; + * } + */ diff --git a/guts/open64.c b/guts/open64.c new file mode 100644 index 0000000..0898c78 --- /dev/null +++ b/guts/open64.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_open64(const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(AT_FDCWD, path, flags, mode | O_LARGEFILE); + +/* return rc; + * } + */ diff --git a/guts/openat.c b/guts/openat.c new file mode 100644 index 0000000..9475aeb --- /dev/null +++ b/guts/openat.c @@ -0,0 +1,64 @@ +/* + * static int + * wrap_openat(int dirfd, const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + struct stat64 buf; + int existed = 1; + int save_errno; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } +#endif + /* if a creation has been requested, check whether file exists */ + if (flags & O_CREAT) { + save_errno = errno; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___xstat64(_STAT_VER, path, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0); +#endif + existed = (rc != -1); + if (!existed) + pseudo_debug(2, "openat_creat: %s -> 0%o\n", path, mode); + errno = save_errno; + } + + /* because we are not actually root, secretly mask in 0700 to the + * underlying mode + */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_open(path, flags, PSEUDO_FS_MODE(mode)); +#else + rc = real_openat(dirfd, path, flags, PSEUDO_FS_MODE(mode)); +#endif + save_errno = errno; + + if (rc != -1) { + int stat_rc; +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + stat_rc = real___xstat64(_STAT_VER, path, &buf); +#else + stat_rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, 0); +#endif + + if (stat_rc != -1) { + buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode); + if (!existed) { + pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf); + } + pseudo_client_op(OP_OPEN, 0, rc, dirfd, path, &buf); + } else { + pseudo_debug(1, "openat (fd %d, path %d/%s, flags %d) succeeded, but stat failed (%s).\n", + rc, dirfd, path, flags, strerror(errno)); + pseudo_client_op(OP_OPEN, 0, rc, dirfd, path, 0); + } + errno = save_errno; + } + +/* return rc; + * } + */ diff --git a/guts/openat64.c b/guts/openat64.c new file mode 100644 index 0000000..926d9c8 --- /dev/null +++ b/guts/openat64.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_openat64(int dirfd, const char *path, int flags, ...mode_t mode) { + * int rc = -1; + */ + + rc = wrap_openat(dirfd, path, flags, mode | O_LARGEFILE); + +/* return rc; + * } + */ diff --git a/guts/rename.c b/guts/rename.c new file mode 100644 index 0000000..9dd6d99 --- /dev/null +++ b/guts/rename.c @@ -0,0 +1,77 @@ +/* + * static int + * wrap_rename(const char *oldpath, const char *newpath) { + * int rc = -1; + */ + pseudo_msg_t *msg; + struct stat64 oldbuf, newbuf; + int oldrc, newrc; + int save_errno; + + pseudo_debug(1, "rename: %s->%s\n", + oldpath ? oldpath : "<nil>", + newpath ? newpath : "<nil>"); + + if (!oldpath || !newpath) { + errno = EFAULT; + return -1; + } + + save_errno = errno; + + newrc = real___lxstat64(_STAT_VER, newpath, &newbuf); + oldrc = real___lxstat64(_STAT_VER, oldpath, &oldbuf); + + errno = save_errno; + + rc = real_rename(oldpath, newpath); + if (rc == -1) { + /* we failed, and we don't care why */ + return rc; + } + save_errno = errno; + /* nothing to do for a "rename" of a link to itself */ + if (newrc != -1 && oldrc != -1 && + newbuf.st_dev == oldbuf.st_dev && + newbuf.st_ino == oldbuf.st_ino) { + return rc; + } + + /* rename(3) is not mv(1). rename(file, dir) fails; you must provide + * the corrected path yourself. You can rename over a directory only + * if the source is a directory. Symlinks are simply removed. + * + * If we got here, the real rename call succeeded. That means newpath + * has been unlinked and oldpath has been linked to it. + * + * There are a ton of special cases to error check. I don't check + * for any of them, because in every such case, the underlying rename + * failed, and there is nothing to do. + * The only tricky part is that, because we used to ignore symlinks, + * we may have to rename or remove directory trees even though in + * theory rename can never destroy a directory tree. + */ + + /* newpath must be removed. */ + pseudo_client_op(OP_UNLINK, AT_SYMLINK_NOFOLLOW, -1, -1, newpath, &newbuf); + + /* fill in "correct" details from server */ + msg = pseudo_client_op(OP_STAT, AT_SYMLINK_NOFOLLOW, -1, -1, oldpath, &oldbuf); + if (msg && msg->result == RESULT_SUCCEED) { + pseudo_stat_msg(&oldbuf, msg); + pseudo_debug(1, "renaming %s, got old mode of 0%o\n", oldpath, (int) msg->mode); + } else { + /* create an entry under the old name, which will then be + * renamed; this way, children would get renamed too, if there + * were any. + */ + pseudo_debug(1, "renaming new '%s' [%llu]\n", + oldpath, (unsigned long long) oldbuf.st_ino); + pseudo_client_op(OP_LINK, AT_SYMLINK_NOFOLLOW, -1, -1, oldpath, &oldbuf); + } + pseudo_client_op(OP_RENAME, AT_SYMLINK_NOFOLLOW, -1, -1, newpath, &oldbuf, oldpath); + + errno = save_errno; +/* return rc; + * } + */ diff --git a/guts/renameat.c b/guts/renameat.c new file mode 100644 index 0000000..c5d295f --- /dev/null +++ b/guts/renameat.c @@ -0,0 +1,12 @@ +/* + * static int + * wrap_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + * int rc = -1; + */ + + pseudo_diag("help! unimplemented renameat [%s -> %s].\n", oldpath, newpath); + rc = real_renameat(olddirfd, oldpath, newdirfd, newpath); + +/* return rc; + * } + */ diff --git a/guts/rmdir.c b/guts/rmdir.c new file mode 100644 index 0000000..029e5a2 --- /dev/null +++ b/guts/rmdir.c @@ -0,0 +1,22 @@ +/* + * static int + * wrap_rmdir(const char *path) { + * int rc = -1; + */ + struct stat64 buf; + int save_errno; + + rc = real___lxstat64(_STAT_VER, path, &buf); + if (rc == -1) { + return rc; + } + rc = real_rmdir(path); + save_errno = errno; + if (rc != -1) { + pseudo_client_op(OP_UNLINK, AT_SYMLINK_NOFOLLOW, -1, -1, path, &buf); + } + + errno = save_errno; +/* return rc; + * } + */ diff --git a/guts/setegid.c b/guts/setegid.c new file mode 100644 index 0000000..a24be76 --- /dev/null +++ b/guts/setegid.c @@ -0,0 +1,17 @@ +/* + * static int + * wrap_setegid(gid_t egid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || egid == pseudo_egid || egid == pseudo_rgid || egid == pseudo_sgid) { + pseudo_egid = egid; + pseudo_fgid = egid; + pseudo_client_touchgid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/guts/seteuid.c b/guts/seteuid.c new file mode 100644 index 0000000..42cb3db --- /dev/null +++ b/guts/seteuid.c @@ -0,0 +1,17 @@ +/* + * static int + * wrap_seteuid(uid_t euid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || euid == pseudo_euid || euid == pseudo_ruid || euid == pseudo_suid) { + pseudo_euid = euid; + pseudo_fuid = euid; + pseudo_client_touchuid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/guts/setfsgid.c b/guts/setfsgid.c new file mode 100644 index 0000000..b046c6f --- /dev/null +++ b/guts/setfsgid.c @@ -0,0 +1,16 @@ +/* + * static int + * wrap_setfsgid(gid_t fsgid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || + pseudo_egid == fsgid || pseudo_rgid == fsgid || pseudo_sgid == fsgid) { + pseudo_fgid = fsgid; + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/guts/setfsuid.c b/guts/setfsuid.c new file mode 100644 index 0000000..1b58ce8 --- /dev/null +++ b/guts/setfsuid.c @@ -0,0 +1,16 @@ +/* + * static int + * wrap_setfsuid(uid_t fsuid) { + * int rc = -1; + */ + if (pseudo_euid == 0 || + pseudo_euid == fsuid || pseudo_ruid == fsuid || pseudo_suid == fsuid) { + pseudo_fuid = fsuid; + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/guts/setgid.c b/guts/setgid.c new file mode 100644 index 0000000..0bb5f27 --- /dev/null +++ b/guts/setgid.c @@ -0,0 +1,24 @@ +/* + * static int + * wrap_setgid(gid_t gid) { + * int rc = -1; + */ + if (pseudo_euid == 0) { + pseudo_rgid = gid; + pseudo_egid = gid; + pseudo_sgid = gid; + pseudo_fgid = gid; + pseudo_client_touchgid(); + rc = 0; + } else if (pseudo_egid == gid || pseudo_sgid == gid || pseudo_rgid == gid) { + pseudo_egid = gid; + pseudo_fgid = gid; + pseudo_client_touchgid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/guts/setgroups.c b/guts/setgroups.c new file mode 100644 index 0000000..d6856f2 --- /dev/null +++ b/guts/setgroups.c @@ -0,0 +1,12 @@ +/* + * static int + * wrap_setgroups(size_t size, const gid_t *list) { + * int rc = -1; + */ + + /* you always have all group privileges. we're like magic! */ + rc = 0; + +/* return rc; + * } + */ diff --git a/guts/setregid.c b/guts/setregid.c new file mode 100644 index 0000000..2444390 --- /dev/null +++ b/guts/setregid.c @@ -0,0 +1,27 @@ +/* + * static int + * wrap_setregid(gid_t rgid, gid_t egid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && rgid != -1 && + rgid != pseudo_egid && rgid != pseudo_rgid && rgid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && egid != -1 && + egid != pseudo_egid && egid != pseudo_rgid && egid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (rgid != -1) + pseudo_rgid = rgid; + if (egid != -1) + pseudo_egid = egid; + pseudo_fgid = pseudo_egid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/guts/setresgid.c b/guts/setresgid.c new file mode 100644 index 0000000..455fe62 --- /dev/null +++ b/guts/setresgid.c @@ -0,0 +1,34 @@ +/* + * static int + * wrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && rgid != -1 && + rgid != pseudo_egid && rgid != pseudo_rgid && rgid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && egid != -1 && + egid != pseudo_egid && egid != pseudo_rgid && egid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && sgid != -1 && + sgid != pseudo_egid && sgid != pseudo_rgid && sgid != pseudo_sgid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (rgid != -1) + pseudo_rgid = rgid; + if (egid != -1) + pseudo_egid = egid; + if (sgid != -1) + pseudo_sgid = sgid; + pseudo_fgid = pseudo_egid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/guts/setresuid.c b/guts/setresuid.c new file mode 100644 index 0000000..41dd81d --- /dev/null +++ b/guts/setresuid.c @@ -0,0 +1,34 @@ +/* + * static int + * wrap_setresuid(uid_t ruid, uid_t euid, uid_t suid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && ruid != -1 && + ruid != pseudo_euid && ruid != pseudo_ruid && ruid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && euid != -1 && + euid != pseudo_euid && euid != pseudo_ruid && euid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && suid != -1 && + suid != pseudo_euid && suid != pseudo_ruid && suid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (ruid != -1) + pseudo_ruid = ruid; + if (euid != -1) + pseudo_euid = euid; + if (suid != -1) + pseudo_suid = suid; + pseudo_fuid = pseudo_euid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/guts/setreuid.c b/guts/setreuid.c new file mode 100644 index 0000000..3669581 --- /dev/null +++ b/guts/setreuid.c @@ -0,0 +1,27 @@ +/* + * static int + * wrap_setreuid(uid_t ruid, uid_t euid) { + * int rc = -1; + */ + rc = 0; + if (pseudo_euid != 0 && ruid != -1 && + ruid != pseudo_euid && ruid != pseudo_ruid && ruid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (pseudo_euid != 0 && euid != -1 && + euid != pseudo_euid && euid != pseudo_ruid && euid != pseudo_suid) { + rc = -1; + errno = EPERM; + } + if (rc != -1) { + if (ruid != -1) + pseudo_ruid = ruid; + if (euid != -1) + pseudo_euid = euid; + pseudo_fuid = pseudo_euid; + pseudo_client_touchuid(); + } +/* return rc; + * } + */ diff --git a/guts/setuid.c b/guts/setuid.c new file mode 100644 index 0000000..bedebb6 --- /dev/null +++ b/guts/setuid.c @@ -0,0 +1,24 @@ +/* + * static int + * wrap_setuid(uid_t uid) { + * int rc = -1; + */ + if (pseudo_euid == 0) { + pseudo_ruid = uid; + pseudo_euid = uid; + pseudo_suid = uid; + pseudo_fuid = uid; + pseudo_client_touchuid(); + rc = 0; + } else if (pseudo_euid == uid || pseudo_suid == uid || pseudo_ruid == uid) { + pseudo_euid = uid; + pseudo_fuid = uid; + pseudo_client_touchuid(); + rc = 0; + } else { + rc = -1; + errno = EPERM; + } +/* return rc; + * } + */ diff --git a/guts/symlink.c b/guts/symlink.c new file mode 100644 index 0000000..bc1c4be --- /dev/null +++ b/guts/symlink.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_symlink(const char *oldpath, const char *newpath) { + * int rc = -1; + */ + + rc = wrap_symlinkat(oldpath, AT_FDCWD, newpath); + +/* return rc; + * } + */ diff --git a/guts/symlinkat.c b/guts/symlinkat.c new file mode 100644 index 0000000..5f1cc59 --- /dev/null +++ b/guts/symlinkat.c @@ -0,0 +1,38 @@ +/* + * static int + * wrap_symlinkat(const char *oldpath, int dirfd, const char *newpath) { + * int rc = -1; + */ + struct stat64 buf; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + rc = real_symlink(oldpath, newpath); +#else + rc = real_symlinkat(oldpath, dirfd, newpath); +#endif + + if (rc == -1) { + return rc; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___lxstat64(_STAT_VER, newpath, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, newpath, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc == -1) { + int save_errno = errno; + pseudo_diag("symlinkat: couldn't stat '%s' even though symlink creation succeeded (%s).\n", + newpath, strerror(errno)); + errno = save_errno; + return rc; + } + /* just record the entry */ + pseudo_client_op(OP_SYMLINK, AT_SYMLINK_NOFOLLOW, -1, dirfd, newpath, &buf); + +/* return rc; + * } + */ diff --git a/guts/unlink.c b/guts/unlink.c new file mode 100644 index 0000000..369089b --- /dev/null +++ b/guts/unlink.c @@ -0,0 +1,11 @@ +/* + * static int + * wrap_unlink(const char *path) { + * int rc = -1; + */ + + rc = wrap_unlinkat(AT_FDCWD, path, 0); + +/* return rc; + * } + */ diff --git a/guts/unlinkat.c b/guts/unlinkat.c new file mode 100644 index 0000000..cfa71e7 --- /dev/null +++ b/guts/unlinkat.c @@ -0,0 +1,44 @@ +/* + * static int + * wrap_unlinkat(int dirfd, const char *path, int flags) { + * int rc = -1; + */ +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + if (dirfd != AT_FDCWD) { + errno = ENOSYS; + return -1; + } + if (flags) { + /* the only supported flag is AT_REMOVEDIR. We'd never call + * with that flag unless the real AT functions exist, so + * something must have gone horribly wrong.... + */ + pseudo_diag("wrap_unlinkat called with flags (0x%x), path '%s'\n", + flags, path ? path : "<nil>"); + errno = ENOSYS; + return -1; + } +#endif + + struct stat64 buf; + +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real___lxstat64(_STAT_VER, path, &buf); +#else + rc = real___fxstatat64(_STAT_VER, dirfd, path, &buf, AT_SYMLINK_NOFOLLOW); +#endif + if (rc == -1) { + return rc; + } +#ifdef PSEUDO_NO_REAL_AT_FUNCTIONS + rc = real_unlink(path); +#else + rc = real_unlinkat(dirfd, path, flags); +#endif + if (rc != -1) { + pseudo_client_op(OP_UNLINK, AT_SYMLINK_NOFOLLOW, -1, dirfd, path, &buf); + } + +/* return rc; + * } + */ diff --git a/guts/vfork.c b/guts/vfork.c new file mode 100644 index 0000000..7d234da --- /dev/null +++ b/guts/vfork.c @@ -0,0 +1,14 @@ +/* + * static int + * wrap_vfork(void) { + * int rc = -1; + */ + + /* like fakeroot, we really can't handle vfork's implications */ + rc = real_fork(); + if (rc == 0) + pseudo_client_reset(); + +/* return rc; + * } + */ |