From af903024535eaeddbd0574b75a5d19c9e39eafe2 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 21 Sep 2010 21:46:49 +0200 Subject: [PATCH] libmount: add routines for uid=, git= and context= translation Signed-off-by: Karel Zak --- shlibs/mount/src/mount.h.in | 4 + shlibs/mount/src/mount.sym | 3 + shlibs/mount/src/optstr.c | 198 ++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index 42496ac7..6839da9e 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -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 { diff --git a/shlibs/mount/src/mount.sym b/shlibs/mount/src/mount.sym index fe708319..b0fc5312 100644 --- a/shlibs/mount/src/mount.sym +++ b/shlibs/mount/src/mount.sym @@ -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; diff --git a/shlibs/mount/src/optstr.c b/shlibs/mount/src/optstr.c index c35777f2..839d63c7 100644 --- a/shlibs/mount/src/optstr.c +++ b/shlibs/mount/src/optstr.c @@ -19,6 +19,15 @@ #include #include #include +#include +#include + +#ifdef HAVE_LIBSELINUX +#include +#include +#endif + +#include #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=" 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=" 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, " remove name in optstr" }, { "--split", test_split, " split into FS, VFS and userspace" }, { "--flags", test_flags, " convert options to MS_* flags" }, + { "--trans", test_trans, " translate uid=, gid= and context=" }, + { NULL } }; return mnt_run_test(tss, argc, argv); -- 2.39.5