aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Seebach <seebs@eee12.(none)>2010-03-29 17:58:46 -0500
committerPeter Seebach <seebs@eee12.(none)>2010-03-29 17:58:46 -0500
commitfa580977cc4fa8b58a47c483c1a59df66645a120 (patch)
tree42e77c1592e7fa56af0df2d2b86f398a24e119ee
parent2b57c61b7eeb203cfcda848cc93113ec39a639cc (diff)
downloadpseudo-fa580977cc4fa8b58a47c483c1a59df66645a120.tar.gz
pseudo-fa580977cc4fa8b58a47c483c1a59df66645a120.tar.bz2
pseudo-fa580977cc4fa8b58a47c483c1a59df66645a120.zip
Add password/group call emulation.
This is a first pass at handling password/group calls, allowing the use of custom password/group files. In particular, when chroot()ed to a particular directory, pseudo picks files in that directory by default, to improve support for the typical use case where pseudo uses chroot() only to jump into a virtual target filesystem.
-rw-r--r--guts/README31
-rw-r--r--guts/endgrent.c11
-rw-r--r--guts/endpwent.c11
-rw-r--r--guts/fopen.c2
-rw-r--r--guts/fopen64.c2
-rw-r--r--guts/getgrent.c18
-rw-r--r--guts/getgrent_r.c21
-rw-r--r--guts/getgrgid.c18
-rw-r--r--guts/getgrgid_r.c26
-rw-r--r--guts/getgrnam.c20
-rw-r--r--guts/getgrnam_r.c24
-rw-r--r--guts/getgrouplist.c39
-rw-r--r--guts/getgroups.c15
-rw-r--r--guts/getpw.c30
-rw-r--r--guts/getpwent.c18
-rw-r--r--guts/getpwent_r.c14
-rw-r--r--guts/getpwnam.c18
-rw-r--r--guts/getpwnam_r.c23
-rw-r--r--guts/getpwuid.c18
-rw-r--r--guts/getpwuid_r.c23
-rw-r--r--guts/setgrent.c11
-rw-r--r--guts/setpwent.c11
-rwxr-xr-xmakewrappers78
-rw-r--r--pseudo.117
-rw-r--r--pseudo.c13
-rw-r--r--pseudo.h3
-rw-r--r--pseudo_client.c83
-rw-r--r--pseudo_client.h7
-rw-r--r--pseudo_util.c44
-rw-r--r--wrapfuncs.in20
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
diff --git a/pseudo.1 b/pseudo.1
index e2317f3..83d9fe7 100644
--- a/pseudo.1
+++ b/pseudo.1
@@ -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
diff --git a/pseudo.c b/pseudo.c
index 0f5d935..45537dc 100644
--- a/pseudo.c
+++ b/pseudo.c
@@ -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);
diff --git a/pseudo.h b/pseudo.h
index 93f3e89..91b4dc7 100644
--- a/pseudo.h
+++ b/pseudo.h
@@ -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);