[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v5 2/5] util: Create virFileAccessibleAs function



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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]