static int fprintf_utab_fs(FILE *f, struct libmnt_fs *fs) { char *p; int rc = 0; assert(fs); assert(f); if (!fs || !f) return -EINVAL; p = mangle(mnt_fs_get_source(fs)); if (p) { rc = fprintf(f, "SRC=%s ", p); free(p); } if (rc >= 0) { p = mangle(mnt_fs_get_target(fs)); if (p) { rc = fprintf(f, "TARGET=%s ", p); free(p); } } if (rc >= 0) { p = mangle(mnt_fs_get_root(fs)); if (p) { rc = fprintf(f, "ROOT=%s ", p); free(p); } } if (rc >= 0) { p = mangle(mnt_fs_get_bindsrc(fs)); if (p) { rc = fprintf(f, "BINDSRC=%s ", p); free(p); } } if (rc >= 0) { p = mangle(mnt_fs_get_attributes(fs)); if (p) { rc = fprintf(f, "ATTRS=%s ", p); free(p); } } if (rc >= 0) { p = mangle(mnt_fs_get_user_options(fs)); if (p) { rc = fprintf(f, "OPTS=%s", p); free(p); } } if (rc >= 0) rc = fprintf(f, "\n"); if (rc > 0) rc = 0; /* success */ return rc; }
/* * This function uses @uf to found corresponding record in @tb, then the record * from @tb is updated (user specific mount options are added). * * Note that @uf must contain only user specific mount options instead of * VFS options (note that FS options are ignored). * * Returns modified filesystem (from @tb) or NULL. */ static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct libmnt_fs *uf) { struct libmnt_fs *fs; struct libmnt_iter itr; const char *optstr, *src, *target, *root, *attrs; assert(tb); assert(uf); if (!tb || !uf) return NULL; DBG(TAB, mnt_debug_h(tb, "merging user fs")); src = mnt_fs_get_srcpath(uf); target = mnt_fs_get_target(uf); optstr = mnt_fs_get_user_options(uf); attrs = mnt_fs_get_attributes(uf); root = mnt_fs_get_root(uf); if (!src || !target || !root || (!attrs && !optstr)) return NULL; mnt_reset_iter(&itr, MNT_ITER_BACKWARD); while(mnt_table_next_fs(tb, &itr, &fs) == 0) { const char *s = mnt_fs_get_srcpath(fs), *t = mnt_fs_get_target(fs), *r = mnt_fs_get_root(fs); if (fs->flags & MNT_FS_MERGED) continue; if (s && t && r && !strcmp(t, target) && !strcmp(s, src) && !strcmp(r, root)) break; } if (fs) { DBG(TAB, mnt_debug_h(tb, "found fs -- appending user optstr")); mnt_fs_append_options(fs, optstr); mnt_fs_append_attributes(fs, attrs); mnt_fs_set_bindsrc(fs, mnt_fs_get_bindsrc(uf)); fs->flags |= MNT_FS_MERGED; DBG(TAB, mnt_debug_h(tb, "found fs:")); DBG(TAB, mnt_fs_print_debug(fs, stderr)); } return fs; }
/* * Note that cxt->fs contains relevant mtab entry! */ static int evaluate_permissions(struct libmnt_context *cxt) { struct libmnt_table *fstab; unsigned long u_flags = 0; const char *tgt, *src, *optstr; int rc, ok = 0; struct libmnt_fs *fs; assert(cxt); assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt || !cxt->fs) return -EINVAL; if (!mnt_context_is_restricted(cxt)) return 0; /* superuser mount */ DBG(CXT, mnt_debug_h(cxt, "umount: evaluating permissions")); if (!(cxt->flags & MNT_FL_TAB_APPLIED)) { DBG(CXT, mnt_debug_h(cxt, "cannot find %s in mtab and you are not root", mnt_fs_get_target(cxt->fs))); goto eperm; } if (cxt->user_mountflags & MNT_MS_UHELPER) { /* on uhelper= mount option based helper */ rc = prepare_helper_from_options(cxt, "uhelper"); if (rc) return rc; if (cxt->helper) return 0; /* we'll call /sbin/umount.<uhelper> */ } /* * User mounts has to be in /etc/fstab */ rc = mnt_context_get_fstab(cxt, &fstab); if (rc) return rc; tgt = mnt_fs_get_target(cxt->fs); src = mnt_fs_get_source(cxt->fs); if (mnt_fs_get_bindsrc(cxt->fs)) { src = mnt_fs_get_bindsrc(cxt->fs); DBG(CXT, mnt_debug_h(cxt, "umount: using bind source: %s", src)); } /* If fstab contains the two lines * /dev/sda1 /mnt/zip auto user,noauto 0 0 * /dev/sda4 /mnt/zip auto user,noauto 0 0 * then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail. * So, we must not look for file, but for the pair (dev,file) in fstab. */ fs = mnt_table_find_pair(fstab, src, tgt, MNT_ITER_FORWARD); if (!fs) { /* * It's possible that there is /path/file.img in fstab and * /dev/loop0 in mtab -- then we have to check releation * between loopdev and the file. */ fs = mnt_table_find_target(fstab, tgt, MNT_ITER_FORWARD); if (fs) { const char *dev = mnt_fs_get_srcpath(cxt->fs); /* devname from mtab */ if (!dev || !is_associated_fs(dev, fs)) fs = NULL; } if (!fs) { DBG(CXT, mnt_debug_h(cxt, "umount %s: mtab disagrees with fstab", tgt)); goto eperm; } } /* * User mounting and unmounting is allowed only if fstab contains one * of the options `user', `users' or `owner' or `group'. * * The option `users' allows arbitrary users to mount and unmount - * this may be a security risk. * * The options `user', `owner' and `group' only allow unmounting by the * user that mounted (visible in mtab). */ optstr = mnt_fs_get_user_options(fs); /* FSTAB mount options! */ if (!optstr) goto eperm; if (mnt_optstr_get_flags(optstr, &u_flags, mnt_get_builtin_optmap(MNT_USERSPACE_MAP))) goto eperm; if (u_flags & MNT_MS_USERS) { DBG(CXT, mnt_debug_h(cxt, "umount: promiscuous setting ('users') in fstab")); return 0; } /* * Check user=<username> setting from mtab if there is user, owner or * group option in /etc/fstab */ if (u_flags & (MNT_MS_USER | MNT_MS_OWNER | MNT_MS_GROUP)) { char *curr_user = NULL; char *mtab_user = NULL; size_t sz; DBG(CXT, mnt_debug_h(cxt, "umount: checking user=<username> from mtab")); curr_user = mnt_get_username(getuid()); if (!curr_user) { DBG(CXT, mnt_debug_h(cxt, "umount %s: cannot " "convert %d to username", tgt, getuid())); goto eperm; } /* get options from mtab */ optstr = mnt_fs_get_user_options(cxt->fs); if (optstr && !mnt_optstr_get_option(optstr, "user", &mtab_user, &sz) && sz) ok = !strncmp(curr_user, mtab_user, sz); } if (ok) { DBG(CXT, mnt_debug_h(cxt, "umount %s is allowed", tgt)); return 0; } eperm: DBG(CXT, mnt_debug_h(cxt, "umount is not allowed for you")); return -EPERM; }