diff options
-rw-r--r-- | guts/README | 31 | ||||
-rw-r--r-- | guts/endgrent.c | 11 | ||||
-rw-r--r-- | guts/endpwent.c | 11 | ||||
-rw-r--r-- | guts/fopen.c | 2 | ||||
-rw-r--r-- | guts/fopen64.c | 2 | ||||
-rw-r--r-- | guts/getgrent.c | 18 | ||||
-rw-r--r-- | guts/getgrent_r.c | 21 | ||||
-rw-r--r-- | guts/getgrgid.c | 18 | ||||
-rw-r--r-- | guts/getgrgid_r.c | 26 | ||||
-rw-r--r-- | guts/getgrnam.c | 20 | ||||
-rw-r--r-- | guts/getgrnam_r.c | 24 | ||||
-rw-r--r-- | guts/getgrouplist.c | 39 | ||||
-rw-r--r-- | guts/getgroups.c | 15 | ||||
-rw-r--r-- | guts/getpw.c | 30 | ||||
-rw-r--r-- | guts/getpwent.c | 18 | ||||
-rw-r--r-- | guts/getpwent_r.c | 14 | ||||
-rw-r--r-- | guts/getpwnam.c | 18 | ||||
-rw-r--r-- | guts/getpwnam_r.c | 23 | ||||
-rw-r--r-- | guts/getpwuid.c | 18 | ||||
-rw-r--r-- | guts/getpwuid_r.c | 23 | ||||
-rw-r--r-- | guts/setgrent.c | 11 | ||||
-rw-r--r-- | guts/setpwent.c | 11 | ||||
-rwxr-xr-x | makewrappers | 78 | ||||
-rw-r--r-- | pseudo.1 | 17 | ||||
-rw-r--r-- | pseudo.c | 13 | ||||
-rw-r--r-- | pseudo.h | 3 | ||||
-rw-r--r-- | pseudo_client.c | 83 | ||||
-rw-r--r-- | pseudo_client.h | 7 | ||||
-rw-r--r-- | pseudo_util.c | 44 | ||||
-rw-r--r-- | wrapfuncs.in | 20 |
30 files changed, 636 insertions, 33 deletions
diff --git a/guts/README b/guts/README index e933349..a1030c6 100644 --- a/guts/README +++ b/guts/README @@ -157,3 +157,34 @@ dummied them out: renameat tempnam tmpnam + +The following functions are partially emulated in order to provide for +emulation of various getpw*() and getgr*() functions. No handling is +provided for putpw*() or putgr*(). Nearly everything is ultimately +implemented in terms of fgetpwent_r() and fgetgrent_r(), which are +GNU extensions corresponding to fgetpwent() and fgetgrent(), allowing +pseudo to read password information from an arbitrary stream; the +setpwent() and setgrent() functions are modified to pick /etc/* from +the pseudo_chroot path, if one is set, or from PSEUDO_PASSWD, if that +is set, or else the system /etc/* files. + + endgrent + endpwent + getgrent + getgrent_r + getgrgid + getgrgid_r + getgrnam + getgrnam_r + getgrouplist + getgroups + getpw + getpwent + getpwent_r + getpwnam + getpwnam_r + getpwuid + getpwuid_r + setgrent + setgroups + setpwent diff --git a/guts/endgrent.c b/guts/endgrent.c new file mode 100644 index 0000000..8c40845 --- /dev/null +++ b/guts/endgrent.c @@ -0,0 +1,11 @@ +/* + * static void + * wrap_endgrent(void) { + * + */ + + pseudo_grp_close(); + +/* return; + * } + */ diff --git a/guts/endpwent.c b/guts/endpwent.c new file mode 100644 index 0000000..7180c0c --- /dev/null +++ b/guts/endpwent.c @@ -0,0 +1,11 @@ +/* + * static void + * wrap_endpwent(void) { + * + */ + + pseudo_pwd_close(); + +/* return; + * } + */ diff --git a/guts/fopen.c b/guts/fopen.c index 69d9ce6..15b27f5 100644 --- a/guts/fopen.c +++ b/guts/fopen.c @@ -13,7 +13,7 @@ if (rc) { int fd = fileno(rc); - pseudo_debug(2, "fopen '%s': fd %d\n", path, fd); + pseudo_debug(2, "fopen '%s': fd %d <FILE %p>\n", path, fd, (void *) rc); if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { if (!existed) { pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); diff --git a/guts/fopen64.c b/guts/fopen64.c index c2286f2..78cfdaa 100644 --- a/guts/fopen64.c +++ b/guts/fopen64.c @@ -14,7 +14,7 @@ if (rc) { int fd = fileno(rc); - pseudo_debug(2, "fopen64 '%s': fd %d\n", path, fd); + pseudo_debug(2, "fopen64 '%s': fd %d <FILE %p>\n", path, fd, (void *) rc); if (real___fxstat64(_STAT_VER, fd, &buf) != -1) { if (!existed) { pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf); diff --git a/guts/getgrent.c b/guts/getgrent.c new file mode 100644 index 0000000..0be9ec5 --- /dev/null +++ b/guts/getgrent.c @@ -0,0 +1,18 @@ +/* + * static struct group * + * wrap_getgrent(void) { + * struct group * rc = NULL; + */ + static struct group grp; + static char grbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getgrent_r(&grp, grbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/guts/getgrent_r.c b/guts/getgrent_r.c new file mode 100644 index 0000000..6bb9667 --- /dev/null +++ b/guts/getgrent_r.c @@ -0,0 +1,21 @@ +/* + * static int + * wrap_getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + * int rc = -1; + */ + + /* note that we don't wrap fgetgrent_r, since there's no path + * references in it. + */ + rc = fgetgrent_r(pseudo_grp, gbuf, buf, buflen, gbufp); + if (rc == 0 && *gbufp) { + if (*gbufp == gbuf) { + pseudo_debug(1, "found group: %d/%s\n", gbuf->gr_gid, gbuf->gr_name); + } else { + pseudo_debug(1, "found group, but it's wrong?"); + } + } + +/* return rc; + * } + */ diff --git a/guts/getgrgid.c b/guts/getgrgid.c new file mode 100644 index 0000000..20c85c9 --- /dev/null +++ b/guts/getgrgid.c @@ -0,0 +1,18 @@ +/* + * static struct group * + * wrap_getgrgid(gid_t gid) { + * struct group * rc = NULL; + */ + static struct group grp; + static char grbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getgrgid_r(gid, &grp, grbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/guts/getgrgid_r.c b/guts/getgrgid_r.c new file mode 100644 index 0000000..4ae6a93 --- /dev/null +++ b/guts/getgrgid_r.c @@ -0,0 +1,26 @@ +/* + * static int + * wrap_getgrgid_r(gid_t gid, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + * int rc = -1; + */ + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, buflen, gbufp)) == 0) { + /* 0 means no error occurred, and *gbufp == gbuf */ + if (gbuf->gr_gid == gid) { + pseudo_debug(1, "found group gid %d, name %s\n", + gbuf->gr_gid, gbuf->gr_name); + return rc; + } + } + endgrent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *gbufp = NULL; + +/* return rc; + * } + */ diff --git a/guts/getgrnam.c b/guts/getgrnam.c new file mode 100644 index 0000000..191fe25 --- /dev/null +++ b/guts/getgrnam.c @@ -0,0 +1,20 @@ +/* + * static struct group * + * wrap_getgrnam(const char *name) { + * struct group * rc = NULL; + */ + + static struct group grp; + static char grbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getgrnam_r(name, &grp, grbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + + +/* return rc; + * } + */ diff --git a/guts/getgrnam_r.c b/guts/getgrnam_r.c new file mode 100644 index 0000000..f70bbdc --- /dev/null +++ b/guts/getgrnam_r.c @@ -0,0 +1,24 @@ +/* + * static int + * wrap_getgrnam_r(const char *name, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp) { + * int rc = -1; + */ + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, buflen, gbufp)) == 0) { + /* 0 means no error occurred, and *gbufp == gbuf */ + if (gbuf->gr_name && !strcmp(gbuf->gr_name, name)) + return rc; + } + endgrent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *gbufp = NULL; + + +/* return rc; + * } + */ diff --git a/guts/getgrouplist.c b/guts/getgrouplist.c new file mode 100644 index 0000000..ef362bb --- /dev/null +++ b/guts/getgrouplist.c @@ -0,0 +1,39 @@ +/* + * static int + * wrap_getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups) { + * int rc = -1; + */ + + int found = 0; + int found_group = 0; + char buf[PSEUDO_PWD_MAX]; + struct group grp, *gbuf = &grp; + + setgrent(); + while ((rc = wrap_getgrent_r(gbuf, buf, PSEUDO_PWD_MAX, &gbuf)) == 0) { + int i = 0; + for (i = 0; gbuf->gr_mem[i]; ++i) { + if (!strcmp(gbuf->gr_mem[i], user)) { + if (found < *ngroups) + groups[found] = gbuf->gr_gid; + ++found; + if (gbuf->gr_gid == group) + found_group = 1; + } + } + } + endgrent(); + if (!found_group) { + if (found < *ngroups) + groups[found] = group; + ++found; + } + if (found >= *ngroups) + rc = -1; + else + rc = found; + *ngroups = found; + +/* return rc; + * } + */ diff --git a/guts/getgroups.c b/guts/getgroups.c new file mode 100644 index 0000000..8394325 --- /dev/null +++ b/guts/getgroups.c @@ -0,0 +1,15 @@ +/* + * static int + * wrap_getgroups(int size, gid_t *list) { + * int rc = -1; + */ + + /* you're only in group zero */ + rc = 1; + if (size > 0) { + list[0] = 0; + } + +/* return rc; + * } + */ diff --git a/guts/getpw.c b/guts/getpw.c new file mode 100644 index 0000000..cf41799 --- /dev/null +++ b/guts/getpw.c @@ -0,0 +1,30 @@ +/* + * static int + * wrap_getpw(uid_t uid, char *buf) { + * int rc = -1; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + struct passwd *pwp; + + pseudo_diag("warning: unsafe getpw() called. hoping buf has at least %d chars.\n", + PSEUDO_PWD_MAX); + rc = wrap_getpwuid_r(uid, &pwd, pwbuf, PSEUDO_PWD_MAX, &pwp); + /* different error return conventions */ + if (rc != 0) { + errno = rc; + rc = -1; + } else { + snprintf(buf, PSEUDO_PWD_MAX, "%s:%s:%d:%d:%s:%s:%s", + pwd.pw_name, + pwd.pw_passwd, + pwd.pw_uid, + pwd.pw_gid, + pwd.pw_gecos, + pwd.pw_dir, + pwd.pw_shell); + } + +/* return rc; + * } + */ diff --git a/guts/getpwent.c b/guts/getpwent.c new file mode 100644 index 0000000..5b76ad0 --- /dev/null +++ b/guts/getpwent.c @@ -0,0 +1,18 @@ +/* + * static struct passwd * + * wrap_getpwent(void) { + * struct passwd * rc = NULL; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getpwent_r(&pwd, pwbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/guts/getpwent_r.c b/guts/getpwent_r.c new file mode 100644 index 0000000..2bf1db2 --- /dev/null +++ b/guts/getpwent_r.c @@ -0,0 +1,14 @@ +/* + * static int + * wrap_getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + * int rc = -1; + */ + + /* note that we don't wrap fgetpwent_r, since there's no path + * references in it. + */ + return fgetpwent_r(pseudo_pwd, pwbuf, buf, buflen, pwbufp); + +/* return rc; + * } + */ diff --git a/guts/getpwnam.c b/guts/getpwnam.c new file mode 100644 index 0000000..04aed89 --- /dev/null +++ b/guts/getpwnam.c @@ -0,0 +1,18 @@ +/* + * static struct passwd * + * wrap_getpwnam(const char *name) { + * struct passwd * rc = NULL; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getpwnam_r(name, &pwd, pwbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/guts/getpwnam_r.c b/guts/getpwnam_r.c new file mode 100644 index 0000000..d292cdb --- /dev/null +++ b/guts/getpwnam_r.c @@ -0,0 +1,23 @@ +/* + * static int + * wrap_getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + * int rc = -1; + */ + + setpwent(); + while ((rc = wrap_getpwent_r(pwbuf, buf, buflen, pwbufp)) == 0) { + /* 0 means no error occurred, and *pwbufp == pwbuf */ + if (pwbuf->pw_name && !strcmp(pwbuf->pw_name, name)) + return rc; + } + endpwent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *pwbufp = NULL; + +/* return rc; + * } + */ diff --git a/guts/getpwuid.c b/guts/getpwuid.c new file mode 100644 index 0000000..9407405 --- /dev/null +++ b/guts/getpwuid.c @@ -0,0 +1,18 @@ +/* + * static struct passwd * + * wrap_getpwuid(uid_t uid) { + * struct passwd * rc = NULL; + */ + static struct passwd pwd; + static char pwbuf[PSEUDO_PWD_MAX]; + int r_rc; + + r_rc = wrap_getpwuid_r(uid, &pwd, pwbuf, PSEUDO_PWD_MAX, &rc); + /* different error return conventions */ + if (r_rc != 0) { + errno = r_rc; + } + +/* return rc; + * } + */ diff --git a/guts/getpwuid_r.c b/guts/getpwuid_r.c new file mode 100644 index 0000000..f2b6afb --- /dev/null +++ b/guts/getpwuid_r.c @@ -0,0 +1,23 @@ +/* + * static int + * wrap_getpwuid_r(uid_t uid, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp) { + * int rc = -1; + */ + + setpwent(); + while ((rc = wrap_getpwent_r(pwbuf, buf, buflen, pwbufp)) == 0) { + /* 0 means no error occurred, and *pwbufp == pwbuf */ + if (pwbuf->pw_uid == uid) + return rc; + } + endpwent(); + /* we never found a match; rc is 0 if there was no error, or + * non-zero if an error occurred. Either way, set the + * pwbufp pointer to NULL to indicate that we didn't find + * something, and leave rc alone. + */ + *pwbufp = NULL; + +/* return rc; + * } + */ diff --git a/guts/setgrent.c b/guts/setgrent.c new file mode 100644 index 0000000..c840de0 --- /dev/null +++ b/guts/setgrent.c @@ -0,0 +1,11 @@ +/* + * static void + * wrap_setgrent(void) { + * + */ + + pseudo_grp_open(); + +/* return; + * } + */ diff --git a/guts/setpwent.c b/guts/setpwent.c new file mode 100644 index 0000000..3941e67 --- /dev/null +++ b/guts/setpwent.c @@ -0,0 +1,11 @@ +/* + * static void + * wrap_setpwent(void) { + * + */ + + pseudo_pwd_open(); + +/* return; + * } + */ diff --git a/makewrappers b/makewrappers index 905372f..5dcf1d4 100755 --- a/makewrappers +++ b/makewrappers @@ -51,11 +51,6 @@ cat >&5 <<EOF #include <string.h> #include <errno.h> #include <pthread.h> -#include <dirent.h> -#include <fts.h> -#include <ftw.h> -#include <glob.h> -#include <utime.h> #include <sys/types.h> #include <unistd.h> @@ -63,6 +58,15 @@ cat >&5 <<EOF #include <sys/stat.h> #include <dlfcn.h> +/* used for various specific function arguments */ +#include <dirent.h> +#include <fts.h> +#include <ftw.h> +#include <glob.h> +#include <grp.h> +#include <pwd.h> +#include <utime.h> + #include "pseudo.h" #include "pseudo_wrappers.h" #include "pseudo_ipc.h" @@ -268,16 +272,42 @@ do done # determine default return value. + is_void=false case $type in int|ssize_t|long) default_value=-1;; uid_t|gid_t) default_value=0;; - 'FILE *' | 'char *' | 'DIR *' | 'FTS *') + *'*') default_value=NULL;; + void) + is_void=true + default_value='' + ;; *) echo >&2 " Unknown type '$type'." ; exit 1 ;; esac + if $is_void; then + write_return() { + printf "return" + } + write_assign() { + printf "(void)" + } + write_decl() { + : # do nothing + } + else + write_return() { + printf "return %s" "$1" + } + write_assign() { + printf "%s =" "$1" + } + write_decl() { + printf "%s %s = %s;" "$1" "$2" "$3" + } + fi # create the wrappers # first the dummy, and the function pointer: cat >&5 <<EOF @@ -285,7 +315,7 @@ static $type dummy_$name($dummy_args) { pseudo_enosys("$name"); errno = ENOSYS; - return $default_value; + $(write_return $default_value); } static $type (*real_$name)($args) = dummy_$name; @@ -314,32 +344,32 @@ EOF pseudo_debug(4, "called: $name\n"); if (pseudo_getlock()) { errno = EBUSY; - return $default_value; + $(write_return $default_value); } $decl_paths if (pseudo_populate_wrappers()) { - $type rc = $default_value; + $(write_decl "$type" "rc" "$default_value") int save_errno; if (antimagic > 0) { if (real_$name) { - rc = (*real_$name)($argnames); + $(write_assign rc) (*real_$name)($argnames); } else { - rc = dummy_$name($argnames); + $(write_assign rc) dummy_$name($argnames); } } else { $alloc_paths - rc = wrap_$name($argnames); + $(write_assign rc) wrap_$name($argnames); $free_paths } save_errno = errno; pseudo_droplock(); errno = save_errno; pseudo_debug(4, "completed: $name\n"); - return rc; + $(write_return rc); } else { pseudo_droplock(); pseudo_debug(4, "completed: $name\n"); - return dummy_$name($argnames); + $(write_return "dummy_$name($argnames)"); } } @@ -357,7 +387,7 @@ EOF cat >&5 << EOF static $type wrap_$name($args) { - $type rc = $default_value; + $(write_decl "$type" "rc" "$default_value") $optional_decl; va_list ap; @@ -367,18 +397,18 @@ wrap_$name($args) { #include "$guts" - return rc; + $(write_return rc); } EOF else cat >&5 << EOF static $type wrap_$name($args) { - $type rc = $default_value; + $(write_decl "$type" "rc" "$default_value") #include "$guts" - return rc; + $(write_return rc); } EOF fi @@ -390,12 +420,12 @@ EOF /* * static $type * wrap_$name($args$optional_decl) { - * $type rc = $default_value; + * $(write_decl "$type" "rc" "$default_value") */ - rc = real_$name($wrapargnames); + $(write_assign rc) real_$name($wrapargnames); -/* return rc; +/* $(write_return rc); * } */ EOF @@ -404,12 +434,12 @@ EOF /* * static $type * wrap_$name($args) { - * $type rc = $default_value; + * $(write_decl "$type" "rc" "$default_value") */ - rc = real_$name($wrapargnames); + $(write_assign rc) real_$name($wrapargnames); -/* return rc; +/* $(write_return rc); * } */ EOF @@ -303,6 +303,23 @@ to manually run things in the .I pseudo environment. .TP 8 +.B PSEUDO_PASSWD +This variable holds the path to a directory containing password and +group files to use for emulation of various password and group routines. +It should be the path to a directory containing the +.I etc +directory containing files named +.IR passwd and group . +When +.I pseudo +is emulating a +.I chroot +environment, the chroot directory is used by preference. The +parallelism between these cases is why this variable points at +the parent directory of +.I etc +rather than the directory containing the files. +.TP 8 .B PSEUDO_PREFIX If set, the variable .B PSEUDO_PREFIX @@ -93,11 +93,14 @@ main(int argc, char *argv[]) { } unsetenv("PSEUDO_RELOADED"); + /* we need cwd to canonicalize paths */ + pseudo_client_getcwd(); + /* warning: GNU getopt permutes arguments, which is just plain * wrong. The + suppresses this annoying behavior, but may not * be compatible with sane option libraries. */ - while ((o = getopt(argc, argv, "+dfhlP:r:R:St:vV")) != -1) { + while ((o = getopt(argc, argv, "+dfhlp:P:r:R:St:vV")) != -1) { switch (o) { case 'd': /* run as daemon */ @@ -115,8 +118,13 @@ main(int argc, char *argv[]) { "%s-l", optptr > opts ? " " : ""); opt_l = 1; break; + case 'p': + s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW); + if (!s) + pseudo_diag("Can't resolve passwd path '%s'\n", optarg); + setenv("PSEUDO_PASSWD", s, 1); + break; case 'P': - pseudo_client_getcwd(); s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW); if (!s) pseudo_diag("Can't resolve prefix path '%s'\n", optarg); @@ -124,7 +132,6 @@ main(int argc, char *argv[]) { break; case 'r': /* FALLTHROUGH */ case 'R': - pseudo_client_getcwd(); s = PSEUDO_ROOT_PATH(AT_FDCWD, optarg, AT_SYMLINK_NOFOLLOW); if (!s) pseudo_diag("Can't resolve root path '%s'\n", optarg); @@ -127,6 +127,9 @@ extern char *pseudo_prefix_path(char *); extern char *pseudo_get_prefix(char *); extern ssize_t pseudo_sys_path_max(void); extern ssize_t pseudo_path_max(void); +#define PSEUDO_PWD_MAX 4096 +extern int pseudo_etc_file(char *filename, char **search, int dircount); +#define PSEUDO_ETC_FILE(name) pseudo_etc_file((name), (char *[]) { pseudo_chroot, pseudo_passwd }, 2) extern char *pseudo_version; diff --git a/pseudo_client.c b/pseudo_client.c index bd4ab10..6418dea 100644 --- a/pseudo_client.c +++ b/pseudo_client.c @@ -42,13 +42,18 @@ static char *base_path(int dirfd, const char *path, int leave_last); static int connect_fd = -1; static int server_pid = 0; int pseudo_dir_fd = -1; -char *pseudo_cwd = 0; +int pseudo_pwd_fd = -1; +FILE *pseudo_pwd = NULL; +int pseudo_grp_fd = -1; +FILE *pseudo_grp = NULL; +char *pseudo_cwd = NULL; size_t pseudo_cwd_len; -char *pseudo_chroot = 0; +char *pseudo_chroot = NULL; +char *pseudo_passwd = NULL; size_t pseudo_chroot_len = 0; -char *pseudo_cwd_rel = 0; +char *pseudo_cwd_rel = NULL; -static char **fd_paths = 0; +static char **fd_paths = NULL; static int nfds = 0; static int messages = 0; static struct timeval message_time = { .tv_sec = 0 }; @@ -64,6 +69,67 @@ gid_t pseudo_egid; gid_t pseudo_sgid; gid_t pseudo_fgid; +static void +pseudo_file_close(int *fd, FILE **fp) { + if (!fp || !fd) { + pseudo_diag("pseudo_file_close: needs valid pointers.\n"); + return; + } + pseudo_antimagic(); + if (*fp) { + fclose(*fp); + *fd = -1; + *fp = 0; + } + /* this should be impossible */ + if (*fd >= 0) { + close(*fd); + *fd = -1; + } + pseudo_magic(); +} + +static FILE * +pseudo_file_open(char *name, int *fd, FILE **fp) { + if (!fp || !fd || !name) { + pseudo_diag("pseudo_file_open: needs valid pointers.\n"); + return NULL; + } + pseudo_file_close(fd, fp); + pseudo_antimagic(); + *fd = PSEUDO_ETC_FILE(name); + if (*fd >= 0) { + *fd = pseudo_fd(*fd, MOVE_FD); + *fp = fdopen(*fd, "r"); + if (!*fp) { + close(*fd); + *fd = -1; + } + } + pseudo_magic(); + return *fp; +} + +FILE * +pseudo_pwd_open() { + return pseudo_file_open("passwd", &pseudo_pwd_fd, &pseudo_pwd); +} + +void +pseudo_pwd_close() { + pseudo_file_close(&pseudo_pwd_fd, &pseudo_pwd); +} + +FILE * +pseudo_grp_open() { + return pseudo_file_open("group", &pseudo_grp_fd, &pseudo_grp); +} + +void +pseudo_grp_close() { + pseudo_file_close(&pseudo_grp_fd, &pseudo_grp); +} + void pseudo_client_touchuid(void) { static char uidbuf[256]; @@ -238,6 +304,11 @@ pseudo_client_reset() { } } + env = getenv("PSEUDO_PASSWD"); + if (env) { + pseudo_passwd = strdup(env); + } + pseudo_inited = 1; } pseudo_client_getcwd(); @@ -808,6 +879,10 @@ pseudo_client_op(op_id_t op, int access, int fd, int dirfd, const char *path, co pseudo_util_debug_fd = pseudo_fd(fd, COPY_FD); } else if (fd == pseudo_dir_fd) { pseudo_dir_fd = pseudo_fd(fd, COPY_FD); + } else if (fd == pseudo_pwd_fd) { + pseudo_pwd_fd = pseudo_fd(fd, COPY_FD); + } else if (fd == pseudo_grp_fd) { + pseudo_grp_fd = pseudo_fd(fd, COPY_FD); } } pseudo_client_close(fd); diff --git a/pseudo_client.h b/pseudo_client.h index 11d5a0c..e2a36f6 100644 --- a/pseudo_client.h +++ b/pseudo_client.h @@ -40,6 +40,12 @@ extern gid_t pseudo_sgid; extern gid_t pseudo_rgid; extern gid_t pseudo_fgid; extern int pseudo_dir_fd; +extern FILE *pseudo_pwd_open(); +extern FILE *pseudo_grp_open(); +extern void pseudo_pwd_close(); +extern void pseudo_grp_close(); +extern FILE *pseudo_pwd; +extern FILE *pseudo_grp; /* support related to chroot/getcwd/etc. */ extern int pseudo_client_getcwd(void); @@ -50,6 +56,7 @@ extern char *pseudo_cwd; extern size_t pseudo_cwd_len; extern char *pseudo_cwd_rel; extern char *pseudo_chroot; +extern char *pseudo_passwd; extern size_t pseudo_chroot_len; /* Root can read, write, and execute files which have no read, write, diff --git a/pseudo_util.c b/pseudo_util.c index bb60edb..8af3020 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -614,3 +614,47 @@ pseudo_access_fopen(const char *mode) { } return access; } + +/* find a passwd/group file to use + * uses in order: + * - PSEUDO_CHROOT/etc/<file> (only if CHROOT is set) + * - PSEUDO_PASSWD/etc/<file> + * - /etc/<file> + */ + +int +pseudo_etc_file(char *file, char **search_dirs, int dircount) { + char filename[pseudo_path_max()]; + int rc; + + if (!file) { + pseudo_diag("pseudo_etc_file: needs argument, usually passwd/group\n"); + return 0; + } + if (search_dirs) { + char *s; + int i; + for (i = 0; i < dircount; ++i) { + s = search_dirs[i]; + if (!s) + continue; + snprintf(filename, pseudo_path_max(), "%s/etc/%s", + s, file); + rc = open(filename, O_RDONLY); + if (rc >= 0) { + pseudo_debug(2, "using <%s> for <%s>\n", + filename, file); + return rc; + } else { + pseudo_debug(3, "didn't find <%s>\n", + filename); + } + } + } else { + pseudo_debug(2, "pseudo_etc_file: no search dirs.\n"); + } + snprintf(filename, pseudo_path_max(), "/etc/%s", file); + pseudo_debug(2, "falling back on <%s> for <%s>\n", + filename, file); + return open(filename, O_RDONLY); +} diff --git a/wrapfuncs.in b/wrapfuncs.in index 22510dc..26ef1b7 100644 --- a/wrapfuncs.in +++ b/wrapfuncs.in @@ -89,3 +89,23 @@ int truncate(const char *path, off_t length); int utime(const char *path, const struct utimbuf *buf); int utimes(const char *path, const struct timeval *times); int execve(const char *filename, char *const *argv, char *const *envp); +# for emulation of passwd utilities +struct passwd *getpwnam(const char *name); +struct passwd *getpwuid(uid_t uid); +int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); +int getpwuid_r(uid_t uid, struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); +int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, struct passwd **pwbufp); +struct passwd *getpwent(void); +void setpwent(void); +void endpwent(void); +int getpw(uid_t uid, char *buf); +struct group *getgrnam(const char *name); +struct group *getgrgid(gid_t gid); +int getgrnam_r(const char *name, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); +int getgrgid_r(gid_t gid, struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); +struct group *getgrent(void); +int getgrent_r(struct group *gbuf, char *buf, size_t buflen, struct group **gbufp); +void setgrent(void); +void endgrent(void); +int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups); +int getgroups(int size, gid_t *list); |