]> err.no Git - util-linux/commitdiff
libmount: add routines for uid=, git= and context= translation
authorKarel Zak <kzak@redhat.com>
Tue, 21 Sep 2010 19:46:49 +0000 (21:46 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 3 Jan 2011 11:28:42 +0000 (12:28 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
shlibs/mount/src/mount.h.in
shlibs/mount/src/mount.sym
shlibs/mount/src/optstr.c

index 42496ac788dd8725b73dd818cebc3ca44bc41964..6839da9e90913134ef02fd91a2562984402cf3f6 100644 (file)
@@ -172,6 +172,10 @@ extern int mnt_split_optstr(const char *optstr,
 extern int mnt_optstr_get_mountflags(const char *optstr, unsigned long *flags);
 extern int mnt_optstr_get_userspace_mountflags(const char *optstr, unsigned long *flags);
 
+extern int mnt_optstr_translate_gid(char **optstr);
+extern int mnt_optstr_translate_uid(char **optstr);
+extern int mnt_optstr_translate_selinux(char **optstr, const char *name);
+
 /* iter.c */
 enum {
 
index fe708319a6ad7fc55dbe62622ab889a079d25a19..b0fc5312ce42ee65874eee506e35070c33bffb94 100644 (file)
@@ -79,6 +79,9 @@ global:
        mnt_optstr_prepend_option;
        mnt_optstr_remove_option;
        mnt_optstr_set_option;
+       mnt_optstr_translate_gid;
+       mnt_optstr_translate_selinux;
+       mnt_optstr_translate_uid;
        mnt_parse_version_string;
        mnt_reset_iter;
        mnt_resolve_path;
index c35777f2d2fec1bbcd99fb581e70571147e54c47..839d63c7a6411ef37aecffa6b79b7bc838ac0e99 100644 (file)
 #include <stdlib.h>
 #include <ctype.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#endif
+
+#include <ctype.h>
 
 #include "nls.h"
 #include "mountP.h"
@@ -520,6 +529,162 @@ int mnt_optstr_get_userspace_mountflags(const char *optstr, unsigned long *flags
                                    0);
 }
 
+/**
+ * mnt_optstr_translate_selinux:
+ * @optstr: string with comma separated list of options
+ * @name: context option name (fscontext. rootcontext, ...)
+ *
+ * Translates SELinux context from human to raw format. The function does not
+ * modify @optstr and returns zero if libmount is compiled without SELinux
+ * support.
+ *
+ * Returns: 0 on success, negative number in case of error,
+ *          and 1 if not found the @name
+ */
+int mnt_optstr_translate_selinux(char **optstr, const char *name)
+{
+       int rc = 0;
+
+#ifdef HAVE_LIBSELINUX
+       security_context_t raw = NULL;
+       char *val = NULL, *p;
+       size_t valsz = 0;
+
+       /* TODO: it would be more efective to use mnt_optstr_locate_option(),
+        *       save begin and end of the option and after context string
+        *       translation replace stuff between begin and end pointers.
+        *
+        *       See also mnt_context_subst_optstr() where is the same problem
+        *       with uid=/gid=.
+        */
+       rc = mnt_optstr_get_option(*optstr, name, &val, &valsz);
+       if (rc)
+               return rc;
+       if (!valsz)
+               return -EINVAL;
+
+       /* the selinux contexts are quoted */
+       if (*val == '"') {
+               if (valsz <= 2 || *(val + valsz - 1) != '"')
+                       return -EINVAL;         /* improperly quoted option string */
+               val++;
+               valsz -= 2;
+       }
+
+       val = strndup(val, valsz);
+       if (!val)
+               return -ENOMEM;
+
+       /* translate the context */
+       rc = selinux_trans_to_raw_context((security_context_t) val, &raw);
+       free(val);
+       if (rc == -1 || !raw)
+               return -EINVAL;
+
+       /* create quoted string from the raw context */
+       valsz = strlen((char *) raw);
+       if (!valsz)
+               return -EINVAL;
+       p = val = malloc(valsz + 3);
+       if (!val)
+               return -ENOMEM;
+
+       *p++ = '"';
+       memcpy(p, raw, valsz);
+       p += valsz;
+       *p++ = '"';
+       *p = '\0';
+
+       freecon(raw);
+
+       rc = mnt_optstr_set_option(optstr, name, val);
+       free(val);
+#endif
+       return rc;
+}
+
+static int optrstr_set_uint(char **optstr, const char *name, unsigned int num)
+{
+       char buf[40];
+       snprintf(buf, sizeof(buf), "%u", num);
+       return mnt_optstr_set_option(optstr, name, buf);
+}
+
+/**
+ * mnt_optstr_translate_uid:
+ * @optstr: string with comma separated list of options
+ *
+ * Translates "uid=<username>" or "uid=useruid" ro the real UID.
+ *
+ * Returns: 0 on success, negative number in case of error,
+ *          and 1 if not found uid= option.
+ */
+int mnt_optstr_translate_uid(char **optstr)
+{
+       char *val = NULL;
+       size_t valsz = 0;
+       int rc;
+
+       rc = mnt_optstr_get_option(*optstr, "uid", &val, &valsz);
+       if (rc || !val)
+               return rc;
+
+       if (!strncmp(val, "useruid", 7))
+               rc = optrstr_set_uint(optstr, "uid", getuid());
+
+       else if (!isdigit(*val)) {
+               uid_t id;
+               char *p = strndup(val, valsz);
+               if (!p)
+                       return -ENOMEM;
+               rc = mnt_get_uid(p, &id);
+               free(p);
+
+               if (!rc)
+                       rc = optrstr_set_uint(optstr, "uid", id);
+       }
+
+       return rc;
+}
+
+/**
+ * mnt_optstr_translate_gid:
+ * @optstr: string with comma separated list of options
+ *
+ * Translates "gid=<groupname>" or "gid=usergid" to the real GID.
+ *
+ * Returns: 0 on success, negative number in case of error,
+ *          and 1 if not found gid= option.
+ */
+int mnt_optstr_translate_gid(char **optstr)
+{
+       char *val = NULL;
+       size_t valsz = 0;
+       int rc;
+
+       rc = mnt_optstr_get_option(*optstr, "gid", &val, &valsz);
+       if (rc || !val)
+               return rc;
+
+       if (!strncmp(val, "usergid", 7))
+               rc = optrstr_set_uint(optstr, "gid", getgid());
+
+       else if (!isdigit(*val)) {
+               gid_t id;
+               char *p = strndup(val, valsz);
+               if (!p)
+                       return -ENOMEM;
+               rc = mnt_get_gid(p, &id);
+               free(p);
+
+               if (!rc)
+                       rc = optrstr_set_uint(optstr, "gid", id);
+       }
+
+       return rc;
+}
+
+
 #ifdef TEST_PROGRAM
 
 int test_append(struct mtest *ts, int argc, char *argv[])
@@ -678,6 +843,37 @@ int test_remove(struct mtest *ts, int argc, char *argv[])
        return rc;
 }
 
+int test_trans(struct mtest *ts, int argc, char *argv[])
+{
+       char *optstr;
+       int rc;
+
+       if (argc < 2)
+               return -EINVAL;
+
+       optstr = strdup(argv[1]);
+
+       printf("optstr: %s\n", optstr);
+
+       rc = mnt_optstr_translate_uid(&optstr);
+       if (rc < 0)
+               return rc;
+       printf("translated uid: %s\n", optstr);
+
+       rc = mnt_optstr_translate_gid(&optstr);
+       if (rc < 0)
+               return rc;
+       printf("translated gid: %s\n", optstr);
+
+       rc = mnt_optstr_translate_selinux(&optstr, "context");
+       if (rc < 0)
+               return rc;
+       printf("translated context: %s\n", optstr);
+
+       free(optstr);
+       return rc == 1 ? 0 : rc;
+
+}
 
 int main(int argc, char *argv[])
 {
@@ -689,6 +885,8 @@ int main(int argc, char *argv[])
                { "--remove", test_remove, "<optstr> <name>            remove name in optstr" },
                { "--split",  test_split,  "<optstr>                   split into FS, VFS and userspace" },
                { "--flags",  test_flags,  "<optstr>                   convert options to MS_* flags" },
+               { "--trans",  test_trans,  "<optstr>                   translate uid=, gid= and context=" },
+
                { NULL }
        };
        return  mnt_run_test(tss, argc, argv);