Ejemplo n.º 1
0
static int
umount_file (char *arg) {
	struct mntentchn *mc, *fs;
	const char *file, *options;
	int fstab_has_user, fstab_has_users, fstab_has_owner, fstab_has_group;
	int ok;

	if (!*arg) {		/* "" would be expanded to `pwd` */
		die(2, _("Cannot umount \"\"\n"));
		return 0;
	}

	file = canonicalize(arg); /* mtab paths are canonicalized */
	if (verbose > 1)
		printf(_("Trying to umount %s\n"), file);

	mc = getmntdirbackward(file, NULL);
	if (!mc) {
		mc = getmntdevbackward(file, NULL);
		if (mc) {
			struct mntentchn *mc1;

			mc1 = getmntdirbackward(mc->m.mnt_dir, NULL);
			if (!mc1)
				/* 'mc1' must exist, though not necessarily
				    equals to `mc'. Otherwise we go mad. */
				die(EX_SOFTWARE,
				    _("umount: confused when analyzing mtab"));

			if (strcmp(file, mc1->m.mnt_fsname)) {
				/* Something was stacked over `file' on the
				   same mount point. */
				die(EX_FAIL, _("umount: cannot umount %s -- %s is "
				    "mounted over it on the same point."),
				    file, mc1->m.mnt_fsname);
			}
		}
	}
	if (!mc && verbose)
		printf(_("Could not find %s in mtab\n"), file);

	if (restricted) {
		char *mtab_user = NULL;

		if (!mc)
			die(2,
			    _("umount: %s is not mounted (according to mtab)"),
			    file);
		/*
		 * uhelper - unprivileged umount helper
		 * -- external umount (for example HAL mounts)
		 */
		if (external_allowed) {
			char *uhelper = NULL;

			if (mc->m.mnt_opts)
				uhelper = get_value(mc->m.mnt_opts, "uhelper=");
			if (uhelper) {
				int status = 0;
				if (check_special_umountprog(arg, arg,
							uhelper, &status))
					return status;
			}
		}

		/* The 2.4 kernel will generally refuse to mount the same
		   filesystem on the same mount point, but will accept NFS.
		   So, unmounting must be possible. */
		if (!is_mounted_once(file) && strcmp(mc->m.mnt_type,"nfs"))
			die(2,
			    _("umount: it seems %s is mounted multiple times"),
			    file);

		/* 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 = getfs_by_devdir(mc->m.mnt_fsname, mc->m.mnt_dir);
		if (!fs) {
			fs = getfs_by_dir(file);
			if (!fs && !getfs_by_spec(file))
				die (2,
				     _("umount: %s is not in the fstab "
				       "(and you are not root)"),
				     file);

			/* spec could be a file which is loop mounted */
			if (fs && !is_valid_loop(mc, fs))
				die (2, _("umount: %s mount disagrees with "
					  "the fstab"), file);
		}

		/*
		 * 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).
		 */

		options = fs->m.mnt_opts;
		if (!options)
			options = "";
		fstab_has_user = contains(options, "user");
		fstab_has_users = contains(options, "users");
		fstab_has_owner = contains(options, "owner");
		fstab_has_group = contains(options, "group");
		ok = 0;

		if (fstab_has_users)
			ok = 1;

		if (!ok && (fstab_has_user || fstab_has_owner ||
			    fstab_has_group)) {
			char *user = getusername();

			options = mc->m.mnt_opts;
			if (!options)
				options = "";
			mtab_user = get_value(options, "user="******"umount: only %s can unmount %s from %s"),
			     mtab_user ? mtab_user : "******",
			     fs->m.mnt_fsname, fs->m.mnt_dir);
	}

	if (mc)
		return umount_one_bw (file, mc);
	else
		return umount_one (arg, arg, arg, arg, NULL);
}
Ejemplo n.º 2
0
int
main (int argc, char *argv[])
{
  int c;
  int all = 0;
  string_list types = NULL;
  string_list options;
  struct mntentchn *mc, *fs;
  char *file;
  int result = 0;

  setlocale(LC_ALL, "");
  bindtextdomain(PACKAGE, LOCALEDIR);
  textdomain(PACKAGE);

  while ((c = getopt_long (argc, argv, "afhnrt:vV",
			   longopts, NULL)) != EOF)
    switch (c) {
      case 'a':			/* umount everything */
	++all;
	break;
      case 'f':			/* force umount */
	++force;
	break;
      case 'h':			/* help */
	usage (stdout, 0);
	break;
      case 'n':			/* do not write in /etc/mtab */
	++nomtab;
	break;
      case 'r':			/* remount read-only if umount fails */
	++remount;
	break;
      case 'v':			/* make noise */
	++verbose;
	break;
      case 'V':			/* version */
	printf ("umount: %s\n", version);
	exit (0);
      case 't':			/* specify file system type */
	types = parse_list (optarg);
	break;
      case 0:
	break;
      case '?':
      default:
	usage (stderr, 1);
    }

  if (getuid () != geteuid ())
    {
      suid = 1;
      if (all || types || nomtab || force)
	die (2, _("umount: only root can do that"));
    }

  argc -= optind;
  argv += optind;

  if (all) {
       if (types == NULL)
	  types = parse_list("noproc");
       result = umount_all (types);
  } else if (argc < 1) {
       usage (stderr, 2);
  } else while (argc--) {
       file = canonicalize (*argv); /* mtab paths are canonicalized */
       if (verbose > 1)
	  printf(_("Trying to umount %s\n"), file);

       mc = getmntfilesbackward (file, NULL);
       if (!mc && verbose)
	  printf(_("Could not find %s in mtab\n"), file);

       if (suid) {
	  if (!mc)
	    die (2, _("umount: %s is not mounted (according to mtab)"), file);
	  if (getmntfilesbackward (file, mc))
	    die (2, _("umount: it seems %s is mounted multiple times"), file);

	  /* 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 (spec,file) in fstab. */
	  fs = getfsspecfile(mc->mnt_fsname, mc->mnt_dir);
	  if (!fs) {
	    if (!getfsspec (file) && !getfsfile (file))
	      die (2,
		 _("umount: %s is not in the fstab (and you are not root)"),
		 file);
	    else
	      die (2, _("umount: %s mount disagrees with the fstab"), file);
	  }

	  /* User mounting and unmounting is allowed only
	     if fstab contains the option `user' or `users' */
	  /* The option `users' allows arbitrary users to mount
	     and unmount - this may be a security risk. */
	  /* The option `user' only allows unmounting by the user
	     that mounted. */
	  /* The option `owner' only allows (un)mounting by the owner. */
	  /* A convenient side effect is that the user who mounted
	     is visible in mtab. */
	  options = parse_list (fs->mnt_opts);
	  while (options) {
	      if (streq (car (options), "user") ||
		  streq (car (options), "users") ||
		  streq (car (options), "owner"))
		break;
	      options = cdr (options);
	  }
	  if (!options)
	    die (2, _("umount: only root can unmount %s from %s"),
		 fs->mnt_fsname, fs->mnt_dir);
	  if (streq (car (options), "user") ||
	      streq (car (options), "owner")) {
	      char *user = getusername();

	      options = parse_list (mc->mnt_opts);
	      while (options) {
		  char *co = car (options);
		  if (!strncmp(co, "user="******"umount: only %s can unmount %s from %s"),
			      co+5, fs->mnt_fsname, fs->mnt_dir);
		      break;
		  }
		  options = cdr (options);
	      }
	  }
       }

       if (mc)
	    result = umount_one_bw (file, mc);
       else
	    result = umount_one (*argv, *argv, *argv, *argv, NULL);

       argv++;

  }
  exit (result);
}