This function checks if a given path is accessible under
given uid and gid.
---
src/util/util.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/util/util.h | 3 ++
2 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/src/util/util.c b/src/util/util.c
index af27344..7343485 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -671,6 +671,77 @@ virFileIsExecutable(const char *file)
}
#ifndef WIN32
+/* Check that a file is accessible under certain
+ * user & gid.
+ * @mode can be F_OK, or a bitwise combination of R_OK, W_OK, and X_OK.
+ * see 'man access' for more details.
+ * Returns 0 on success, -errno on fail,
+ * >0 on signaled child.
+ */
+int
+virFileAccessibleAs(const char *path, int mode,
+ uid_t uid, gid_t gid)
+{
+ pid_t pid = 0;
+ int waitret, status, ret = 0;
+ int forkRet = 0;
+ bool do_fork = (uid != getuid() || gid != getgid());
+
+ if (do_fork)
+ forkRet = virFork(&pid);
+
+ if (pid < 0) {
+ return -1;
+ }
+
+ if (pid) { /* parent */
+ do {
+ if ((waitret = waitpid(pid, &status, 0)) < 0) {
+ ret = -errno;
+ virKillProcess(pid, SIGKILL);
+ return ret;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ /* child actually returns positive value
+ * anded by 0xFF (see man waitpid @ WEXITSTATUS)
+ */
+
+ if (WIFSIGNALED(status))
+ return WTERMSIG(status);
+
+ return -WEXITSTATUS(status);
+ }
+
+ /* child.
+ * Return positive value here. Parent
+ * will change it to negative one. */
+
+ if (forkRet < 0) {
+ ret = 1;
+ goto childerror;
+ }
+
+ if (do_fork && virSetUIDGID(uid, gid) < 0) {
+ ret = errno;
+ goto childerror;
+ }
+
+ if (access(path, mode) < 0)
+ ret = errno;
+
+childerror:
+ if (do_fork && (ret & 0xFF) != ret) {
+ VIR_WARN("unable to pass desired return value %d", ret);
+ ret = 0xFF;
+ }
+
+ if (do_fork)
+ _exit(ret);
+
+ return -ret;
+}
+
/* return -errno on failure, or 0 on success */
static int
virFileOpenAsNoFork(const char *path, int openflags, mode_t mode,
@@ -993,6 +1064,18 @@ childerror:
#else /* WIN32 */
+int
+virFileAccessibleAs(const char *path ATTRIBUTE_UNUSED,
+ int mode ATTRIBUTE_UNUSED,
+ uid_t uid ATTRIBUTE_UNUSED,
+ git_t gid ATTRIBUTE_UNUSED)
+{
+ virUtilError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("virFileAccessibleAs is not implemented for
WIN32"));
+
+ return -ENOSYS;
+}
+
/* return -errno on failure, or 0 on success */
int virFileOpenAs(const char *path ATTRIBUTE_UNUSED,
int openflags ATTRIBUTE_UNUSED,
diff --git a/src/util/util.h b/src/util/util.h
index c55e852..e869f1b 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -93,6 +93,9 @@ enum {
VIR_FILE_OPEN_AS_UID = (1 << 0),
VIR_FILE_OPEN_FORCE_PERMS = (1 << 1),
};
+int virFileAccessibleAs(const char *path, int mode,
+ uid_t uid, gid_t gid)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
int virFileOpenAs(const char *path, int openflags, mode_t mode,
uid_t uid, gid_t gid,
unsigned int flags)
--
1.7.3.4