diff options
author | Karel Zak <kzak@redhat.com> | 2010-09-21 21:46:49 +0200 |
---|---|---|
committer | Karel Zak <kzak@redhat.com> | 2011-01-03 12:28:42 +0100 |
commit | af903024535eaeddbd0574b75a5d19c9e39eafe2 (patch) | |
tree | 5bd083d52e270a87f243f9b2c0084fac7e7d0173 /shlibs | |
parent | a1e8af753cfe312d22c1b497243ef1f98d97052c (diff) | |
download | util-linux-old-af903024535eaeddbd0574b75a5d19c9e39eafe2.tar.gz |
libmount: add routines for uid=, git= and context= translation
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'shlibs')
-rw-r--r-- | shlibs/mount/src/mount.h.in | 4 | ||||
-rw-r--r-- | shlibs/mount/src/mount.sym | 3 | ||||
-rw-r--r-- | shlibs/mount/src/optstr.c | 198 |
3 files changed, 205 insertions, 0 deletions
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 <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); |