xref: /illumos-gate/usr/src/lib/pyzfs/common/allow.py (revision e8921a52)
19f923083SAlexander Pyhalov#!@PYTHON@
214843421SMatthew Ahrens#
314843421SMatthew Ahrens# CDDL HEADER START
414843421SMatthew Ahrens#
514843421SMatthew Ahrens# The contents of this file are subject to the terms of the
614843421SMatthew Ahrens# Common Development and Distribution License (the "License").
714843421SMatthew Ahrens# You may not use this file except in compliance with the License.
814843421SMatthew Ahrens#
914843421SMatthew Ahrens# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1014843421SMatthew Ahrens# or http://www.opensolaris.org/os/licensing.
1114843421SMatthew Ahrens# See the License for the specific language governing permissions
1214843421SMatthew Ahrens# and limitations under the License.
1314843421SMatthew Ahrens#
1414843421SMatthew Ahrens# When distributing Covered Code, include this CDDL HEADER in each
1514843421SMatthew Ahrens# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1614843421SMatthew Ahrens# If applicable, add the following below this CDDL HEADER, with the
1714843421SMatthew Ahrens# fields enclosed by brackets "[]" replaced with your own identifying
1814843421SMatthew Ahrens# information: Portions Copyright [yyyy] [name of copyright owner]
1914843421SMatthew Ahrens#
2014843421SMatthew Ahrens# CDDL HEADER END
2114843421SMatthew Ahrens#
226d52f363SLori Alt# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
2378f17100SMatthew Ahrens# Copyright (c) 2013 by Delphix. All rights reserved.
24*e8921a52SAndy Fiddaman# Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
2514843421SMatthew Ahrens#
2614843421SMatthew Ahrens
2714843421SMatthew Ahrens"""This module implements the "zfs allow" and "zfs unallow" subcommands.
2814843421SMatthew AhrensThe only public interface is the zfs.allow.do_allow() function."""
2914843421SMatthew Ahrens
3014843421SMatthew Ahrensimport zfs.util
3114843421SMatthew Ahrensimport zfs.dataset
3214843421SMatthew Ahrensimport optparse
3314843421SMatthew Ahrensimport sys
3414843421SMatthew Ahrensimport pwd
3514843421SMatthew Ahrensimport grp
3614843421SMatthew Ahrensimport errno
3714843421SMatthew Ahrens
3814843421SMatthew Ahrens_ = zfs.util._
3914843421SMatthew Ahrens
4014843421SMatthew Ahrensclass FSPerms(object):
4114843421SMatthew Ahrens	"""This class represents all the permissions that are set on a
4214843421SMatthew Ahrens	particular filesystem (not including those inherited)."""
4314843421SMatthew Ahrens
4414843421SMatthew Ahrens	__slots__ = "create", "sets", "local", "descend", "ld"
4514843421SMatthew Ahrens	__repr__ = zfs.util.default_repr
4614843421SMatthew Ahrens
4714843421SMatthew Ahrens	def __init__(self, raw):
4814843421SMatthew Ahrens		"""Create a FSPerms based on the dict of raw permissions
4914843421SMatthew Ahrens		from zfs.ioctl.get_fsacl()."""
5014843421SMatthew Ahrens		# set of perms
5114843421SMatthew Ahrens		self.create = set()
5214843421SMatthew Ahrens
5314843421SMatthew Ahrens		# below are { "Ntype name": set(perms) }
5414843421SMatthew Ahrens		# where N is a number that we just use for sorting,
5514843421SMatthew Ahrens		# type is "user", "group", "everyone", or "" (for sets)
5614843421SMatthew Ahrens		# name is a user, group, or set name, or "" (for everyone)
5714843421SMatthew Ahrens		self.sets = dict()
5814843421SMatthew Ahrens		self.local = dict()
5914843421SMatthew Ahrens		self.descend = dict()
6014843421SMatthew Ahrens		self.ld = dict()
6114843421SMatthew Ahrens
6214843421SMatthew Ahrens		# see the comment in dsl_deleg.c for the definition of whokey
6314843421SMatthew Ahrens		for whokey in raw.keys():
6414843421SMatthew Ahrens			perms = raw[whokey].keys()
6514843421SMatthew Ahrens			whotypechr = whokey[0].lower()
6614843421SMatthew Ahrens			ws = whokey[3:]
6714843421SMatthew Ahrens			if whotypechr == "c":
6814843421SMatthew Ahrens				self.create.update(perms)
6914843421SMatthew Ahrens			elif whotypechr == "s":
7014843421SMatthew Ahrens				nwho = "1" + ws
7114843421SMatthew Ahrens				self.sets.setdefault(nwho, set()).update(perms)
7214843421SMatthew Ahrens			else:
7314843421SMatthew Ahrens				if whotypechr == "u":
7414843421SMatthew Ahrens					try:
7514843421SMatthew Ahrens						name = pwd.getpwuid(int(ws)).pw_name
7614843421SMatthew Ahrens					except KeyError:
7714843421SMatthew Ahrens						name = ws
7814843421SMatthew Ahrens					nwho = "1user " + name
7914843421SMatthew Ahrens				elif whotypechr == "g":
8014843421SMatthew Ahrens					try:
8114843421SMatthew Ahrens						name = grp.getgrgid(int(ws)).gr_name
8214843421SMatthew Ahrens					except KeyError:
8314843421SMatthew Ahrens						name = ws
8414843421SMatthew Ahrens					nwho = "2group " + name
8514843421SMatthew Ahrens				elif whotypechr == "e":
8614843421SMatthew Ahrens					nwho = "3everyone"
8714843421SMatthew Ahrens				else:
8814843421SMatthew Ahrens					raise ValueError(whotypechr)
8914843421SMatthew Ahrens
9014843421SMatthew Ahrens				if whokey[1] == "l":
9114843421SMatthew Ahrens					d = self.local
9214843421SMatthew Ahrens				elif whokey[1] == "d":
9314843421SMatthew Ahrens					d = self.descend
9414843421SMatthew Ahrens				else:
9514843421SMatthew Ahrens					raise ValueError(whokey[1])
9614843421SMatthew Ahrens
9714843421SMatthew Ahrens				d.setdefault(nwho, set()).update(perms)
9814843421SMatthew Ahrens
9914843421SMatthew Ahrens		# Find perms that are in both local and descend, and
10014843421SMatthew Ahrens		# move them to ld.
10114843421SMatthew Ahrens		for nwho in self.local:
10214843421SMatthew Ahrens			if nwho not in self.descend:
10314843421SMatthew Ahrens				continue
10414843421SMatthew Ahrens			# note: these are set operations
10514843421SMatthew Ahrens			self.ld[nwho] = self.local[nwho] & self.descend[nwho]
10614843421SMatthew Ahrens			self.local[nwho] -= self.ld[nwho]
10714843421SMatthew Ahrens			self.descend[nwho] -= self.ld[nwho]
10814843421SMatthew Ahrens
10914843421SMatthew Ahrens	@staticmethod
11014843421SMatthew Ahrens	def __ldstr(d, header):
11114843421SMatthew Ahrens		s = ""
11214843421SMatthew Ahrens		for (nwho, perms) in sorted(d.items()):
11314843421SMatthew Ahrens			# local and descend may have entries where perms
11414843421SMatthew Ahrens			# is an empty set, due to consolidating all
11514843421SMatthew Ahrens			# permissions into ld
11614843421SMatthew Ahrens			if perms:
11714843421SMatthew Ahrens				s += "\t%s %s\n" % \
11814843421SMatthew Ahrens				    (nwho[1:], ",".join(sorted(perms)))
11914843421SMatthew Ahrens		if s:
12014843421SMatthew Ahrens			s = header + s
12114843421SMatthew Ahrens		return s
12214843421SMatthew Ahrens
12314843421SMatthew Ahrens	def __str__(self):
12414843421SMatthew Ahrens		s = self.__ldstr(self.sets, _("Permission sets:\n"))
12514843421SMatthew Ahrens
12614843421SMatthew Ahrens		if self.create:
12714843421SMatthew Ahrens			s += _("Create time permissions:\n")
12814843421SMatthew Ahrens			s += "\t%s\n" % ",".join(sorted(self.create))
12914843421SMatthew Ahrens
13014843421SMatthew Ahrens		s += self.__ldstr(self.local, _("Local permissions:\n"))
13114843421SMatthew Ahrens		s += self.__ldstr(self.descend, _("Descendent permissions:\n"))
13214843421SMatthew Ahrens		s += self.__ldstr(self.ld, _("Local+Descendent permissions:\n"))
13314843421SMatthew Ahrens		return s.rstrip()
13414843421SMatthew Ahrens
13514843421SMatthew Ahrensdef args_to_perms(parser, options, who, perms):
13614843421SMatthew Ahrens	"""Return a dict of raw perms {"whostr" -> {"perm" -> None}}
13714843421SMatthew Ahrens	based on the command-line input."""
13814843421SMatthew Ahrens
13914843421SMatthew Ahrens	# perms is not set if we are doing a "zfs unallow <who> <fs>" to
14014843421SMatthew Ahrens	# remove all of someone's permissions
14114843421SMatthew Ahrens	if perms:
14214843421SMatthew Ahrens		setperms = dict(((p, None) for p in perms if p[0] == "@"))
14314843421SMatthew Ahrens		baseperms = dict(((canonicalized_perm(p), None)
14414843421SMatthew Ahrens		    for p in perms if p[0] != "@"))
14514843421SMatthew Ahrens	else:
14614843421SMatthew Ahrens		setperms = None
14714843421SMatthew Ahrens		baseperms = None
14814843421SMatthew Ahrens
14914843421SMatthew Ahrens	d = dict()
150*e8921a52SAndy Fiddaman
15114843421SMatthew Ahrens	def storeperm(typechr, inheritchr, arg):
15214843421SMatthew Ahrens		assert typechr in "ugecs"
15314843421SMatthew Ahrens		assert inheritchr in "ld-"
15414843421SMatthew Ahrens
15514843421SMatthew Ahrens		def mkwhokey(t):
15614843421SMatthew Ahrens			return "%c%c$%s" % (t, inheritchr, arg)
15714843421SMatthew Ahrens
15814843421SMatthew Ahrens		if baseperms or not perms:
15914843421SMatthew Ahrens			d[mkwhokey(typechr)] = baseperms
16014843421SMatthew Ahrens		if setperms or not perms:
16114843421SMatthew Ahrens			d[mkwhokey(typechr.upper())] = setperms
16214843421SMatthew Ahrens
16314843421SMatthew Ahrens	def decodeid(w, toidfunc, fmt):
16414843421SMatthew Ahrens		try:
16514843421SMatthew Ahrens			return int(w)
16614843421SMatthew Ahrens		except ValueError:
16714843421SMatthew Ahrens			try:
16814843421SMatthew Ahrens				return toidfunc(w)[2]
16914843421SMatthew Ahrens			except KeyError:
17014843421SMatthew Ahrens				parser.error(fmt % w)
17114843421SMatthew Ahrens
17214843421SMatthew Ahrens	if options.set:
17314843421SMatthew Ahrens		storeperm("s", "-", who)
17414843421SMatthew Ahrens	elif options.create:
17514843421SMatthew Ahrens		storeperm("c", "-", "")
17614843421SMatthew Ahrens	else:
17714843421SMatthew Ahrens		for w in who:
17814843421SMatthew Ahrens			if options.user:
17914843421SMatthew Ahrens				id = decodeid(w, pwd.getpwnam,
18014843421SMatthew Ahrens				    _("invalid user %s"))
18114843421SMatthew Ahrens				typechr = "u"
18214843421SMatthew Ahrens			elif options.group:
18314843421SMatthew Ahrens				id = decodeid(w, grp.getgrnam,
18414843421SMatthew Ahrens				    _("invalid group %s"))
18514843421SMatthew Ahrens				typechr = "g"
18614843421SMatthew Ahrens			elif w == "everyone":
18714843421SMatthew Ahrens				id = ""
18814843421SMatthew Ahrens				typechr = "e"
18914843421SMatthew Ahrens			else:
19014843421SMatthew Ahrens				try:
19114843421SMatthew Ahrens					id = pwd.getpwnam(w)[2]
19214843421SMatthew Ahrens					typechr = "u"
19314843421SMatthew Ahrens				except KeyError:
19414843421SMatthew Ahrens					try:
19514843421SMatthew Ahrens						id = grp.getgrnam(w)[2]
19614843421SMatthew Ahrens						typechr = "g"
19714843421SMatthew Ahrens					except KeyError:
19814843421SMatthew Ahrens						parser.error(_("invalid user/group %s") % w)
19914843421SMatthew Ahrens			if options.local:
20014843421SMatthew Ahrens				storeperm(typechr, "l", id)
20114843421SMatthew Ahrens			if options.descend:
20214843421SMatthew Ahrens				storeperm(typechr, "d", id)
20314843421SMatthew Ahrens	return d
20414843421SMatthew Ahrens
20514843421SMatthew Ahrensperms_subcmd = dict(
20614843421SMatthew Ahrens    create=_("Must also have the 'mount' ability"),
20714843421SMatthew Ahrens    destroy=_("Must also have the 'mount' ability"),
208681d9761SEric Taylor    snapshot="",
209681d9761SEric Taylor    rollback="",
21014843421SMatthew Ahrens    clone=_("""Must also have the 'create' ability and 'mount'
21114843421SMatthew Ahrens\t\t\t\tability in the origin file system"""),
21214843421SMatthew Ahrens    promote=_("""Must also have the 'mount'
21314843421SMatthew Ahrens\t\t\t\tand 'promote' ability in the origin file system"""),
21414843421SMatthew Ahrens    rename=_("""Must also have the 'mount' and 'create'
21514843421SMatthew Ahrens\t\t\t\tability in the new parent"""),
21614843421SMatthew Ahrens    receive=_("Must also have the 'mount' and 'create' ability"),
21714843421SMatthew Ahrens    allow=_("Must also have the permission that is being\n\t\t\t\tallowed"),
21814843421SMatthew Ahrens    mount=_("Allows mount/umount of ZFS datasets"),
21914843421SMatthew Ahrens    share=_("Allows sharing file systems over NFS or SMB\n\t\t\t\tprotocols"),
22014843421SMatthew Ahrens    send="",
221842727c2SChris Kirby    hold=_("Allows adding a user hold to a snapshot"),
222842727c2SChris Kirby    release=_("Allows releasing a user hold which\n\t\t\t\tmight destroy the snapshot"),
22399d5e173STim Haley    diff=_("Allows lookup of paths within a dataset,\n\t\t\t\tgiven an object number. Ordinary users need this\n\t\t\t\tin order to use zfs diff"),
22478f17100SMatthew Ahrens    bookmark="",
22514843421SMatthew Ahrens)
22614843421SMatthew Ahrens
22714843421SMatthew Ahrensperms_other = dict(
22814843421SMatthew Ahrens    userprop=_("Allows changing any user property"),
22914843421SMatthew Ahrens    userquota=_("Allows accessing any userquota@... property"),
23014843421SMatthew Ahrens    groupquota=_("Allows accessing any groupquota@... property"),
23114843421SMatthew Ahrens    userused=_("Allows reading any userused@... property"),
23214843421SMatthew Ahrens    groupused=_("Allows reading any groupused@... property"),
23314843421SMatthew Ahrens)
23414843421SMatthew Ahrens
23514843421SMatthew Ahrensdef hasset(ds, setname):
23614843421SMatthew Ahrens	"""Return True if the given setname (string) is defined for this
23714843421SMatthew Ahrens	ds (Dataset)."""
23814843421SMatthew Ahrens	# It would be nice to cache the result of get_fsacl().
23914843421SMatthew Ahrens	for raw in ds.get_fsacl().values():
24014843421SMatthew Ahrens		for whokey in raw.keys():
24114843421SMatthew Ahrens			if whokey[0].lower() == "s" and whokey[3:] == setname:
24214843421SMatthew Ahrens				return True
24314843421SMatthew Ahrens	return False
24414843421SMatthew Ahrens
24514843421SMatthew Ahrensdef canonicalized_perm(permname):
24614843421SMatthew Ahrens	"""Return the canonical name (string) for this permission (string).
24714843421SMatthew Ahrens	Raises ZFSError if it is not a valid permission."""
24814843421SMatthew Ahrens	if permname in perms_subcmd.keys() or permname in perms_other.keys():
24914843421SMatthew Ahrens		return permname
25014843421SMatthew Ahrens	try:
25114843421SMatthew Ahrens		return zfs.dataset.getpropobj(permname).name
25214843421SMatthew Ahrens	except KeyError:
25314843421SMatthew Ahrens		raise zfs.util.ZFSError(errno.EINVAL, permname,
25414843421SMatthew Ahrens		    _("invalid permission"))
255*e8921a52SAndy Fiddaman
25614843421SMatthew Ahrensdef print_perms():
25714843421SMatthew Ahrens	"""Print the set of supported permissions."""
25814843421SMatthew Ahrens	print(_("\nThe following permissions are supported:\n"))
25914843421SMatthew Ahrens	fmt = "%-16s %-14s\t%s"
26014843421SMatthew Ahrens	print(fmt % (_("NAME"), _("TYPE"), _("NOTES")))
26114843421SMatthew Ahrens
262*e8921a52SAndy Fiddaman	for (name, note) in sorted(perms_subcmd.items()):
26314843421SMatthew Ahrens		print(fmt % (name, _("subcommand"), note))
26414843421SMatthew Ahrens
265*e8921a52SAndy Fiddaman	for (name, note) in sorted(perms_other.items()):
26614843421SMatthew Ahrens		print(fmt % (name, _("other"), note))
26714843421SMatthew Ahrens
268*e8921a52SAndy Fiddaman	for (name, prop) in sorted(zfs.dataset.proptable.items()):
26914843421SMatthew Ahrens		if prop.visible and prop.delegatable():
27014843421SMatthew Ahrens			print(fmt % (name, _("property"), ""))
27114843421SMatthew Ahrens
27214843421SMatthew Ahrensdef do_allow():
273842727c2SChris Kirby	"""Implements the "zfs allow" and "zfs unallow" subcommands."""
27414843421SMatthew Ahrens	un = (sys.argv[1] == "unallow")
27514843421SMatthew Ahrens
27614843421SMatthew Ahrens	def usage(msg=None):
27714843421SMatthew Ahrens		parser.print_help()
27814843421SMatthew Ahrens		print_perms()
27914843421SMatthew Ahrens		if msg:
28014843421SMatthew Ahrens			print
28114843421SMatthew Ahrens			parser.exit("zfs: error: " + msg)
28214843421SMatthew Ahrens		else:
28314843421SMatthew Ahrens			parser.exit()
28414843421SMatthew Ahrens
28514843421SMatthew Ahrens	if un:
28614843421SMatthew Ahrens		u = _("""unallow [-rldug] <"everyone"|user|group>[,...]
28714843421SMatthew Ahrens	    [<perm|@setname>[,...]] <filesystem|volume>
28814843421SMatthew Ahrens	unallow [-rld] -e [<perm|@setname>[,...]] <filesystem|volume>
28914843421SMatthew Ahrens	unallow [-r] -c [<perm|@setname>[,...]] <filesystem|volume>
29014843421SMatthew Ahrens	unallow [-r] -s @setname [<perm|@setname>[,...]] <filesystem|volume>""")
29114843421SMatthew Ahrens		verb = _("remove")
29214843421SMatthew Ahrens		sstr = _("undefine permission set")
29314843421SMatthew Ahrens	else:
29414843421SMatthew Ahrens		u = _("""allow <filesystem|volume>
29514843421SMatthew Ahrens	allow [-ldug] <"everyone"|user|group>[,...] <perm|@setname>[,...]
29614843421SMatthew Ahrens	    <filesystem|volume>
29714843421SMatthew Ahrens	allow [-ld] -e <perm|@setname>[,...] <filesystem|volume>
29814843421SMatthew Ahrens	allow -c <perm|@setname>[,...] <filesystem|volume>
29914843421SMatthew Ahrens	allow -s @setname <perm|@setname>[,...] <filesystem|volume>""")
30014843421SMatthew Ahrens		verb = _("set")
30114843421SMatthew Ahrens		sstr = _("define permission set")
30214843421SMatthew Ahrens
30314843421SMatthew Ahrens	parser = optparse.OptionParser(usage=u, prog="zfs")
30414843421SMatthew Ahrens
30514843421SMatthew Ahrens	parser.add_option("-l", action="store_true", dest="local",
30614843421SMatthew Ahrens	    help=_("%s permission locally") % verb)
30714843421SMatthew Ahrens	parser.add_option("-d", action="store_true", dest="descend",
30814843421SMatthew Ahrens	    help=_("%s permission for descendents") % verb)
30914843421SMatthew Ahrens	parser.add_option("-u", action="store_true", dest="user",
31014843421SMatthew Ahrens	    help=_("%s permission for user") % verb)
31114843421SMatthew Ahrens	parser.add_option("-g", action="store_true", dest="group",
31214843421SMatthew Ahrens	    help=_("%s permission for group") % verb)
31314843421SMatthew Ahrens	parser.add_option("-e", action="store_true", dest="everyone",
31414843421SMatthew Ahrens	    help=_("%s permission for everyone") % verb)
31514843421SMatthew Ahrens	parser.add_option("-c", action="store_true", dest="create",
31614843421SMatthew Ahrens	    help=_("%s create time permissions") % verb)
31714843421SMatthew Ahrens	parser.add_option("-s", action="store_true", dest="set", help=sstr)
31814843421SMatthew Ahrens	if un:
31914843421SMatthew Ahrens		parser.add_option("-r", action="store_true", dest="recursive",
32014843421SMatthew Ahrens		    help=_("remove permissions recursively"))
32114843421SMatthew Ahrens
32214843421SMatthew Ahrens	if len(sys.argv) == 3 and not un:
32314843421SMatthew Ahrens		# just print the permissions on this fs
32414843421SMatthew Ahrens
32514843421SMatthew Ahrens		if sys.argv[2] == "-h":
32614843421SMatthew Ahrens			# hack to make "zfs allow -h" work
32714843421SMatthew Ahrens			usage()
3289d48f5d3SWilliam Gorrell		ds = zfs.dataset.Dataset(sys.argv[2], snaps=False)
32914843421SMatthew Ahrens
33014843421SMatthew Ahrens		p = dict()
33114843421SMatthew Ahrens		for (fs, raw) in ds.get_fsacl().items():
33214843421SMatthew Ahrens			p[fs] = FSPerms(raw)
33314843421SMatthew Ahrens
33414843421SMatthew Ahrens		for fs in sorted(p.keys(), reverse=True):
33514843421SMatthew Ahrens			s = _("---- Permissions on %s ") % fs
33614843421SMatthew Ahrens			print(s + "-" * (70-len(s)))
33714843421SMatthew Ahrens			print(p[fs])
33814843421SMatthew Ahrens		return
33914843421SMatthew Ahrens
34014843421SMatthew Ahrens	(options, args) = parser.parse_args(sys.argv[2:])
34114843421SMatthew Ahrens
34214843421SMatthew Ahrens	if sum((bool(options.everyone), bool(options.user),
34314843421SMatthew Ahrens	    bool(options.group))) > 1:
34414843421SMatthew Ahrens		parser.error(_("-u, -g, and -e are mutually exclusive"))
34514843421SMatthew Ahrens
34614843421SMatthew Ahrens	def mungeargs(expected_len):
34714843421SMatthew Ahrens		if un and len(args) == expected_len-1:
34814843421SMatthew Ahrens			return (None, args[expected_len-2])
34914843421SMatthew Ahrens		elif len(args) == expected_len:
35014843421SMatthew Ahrens			return (args[expected_len-2].split(","),
35114843421SMatthew Ahrens			    args[expected_len-1])
35214843421SMatthew Ahrens		else:
35314843421SMatthew Ahrens			usage(_("wrong number of parameters"))
35414843421SMatthew Ahrens
35514843421SMatthew Ahrens	if options.set:
35614843421SMatthew Ahrens		if options.local or options.descend or options.user or \
35714843421SMatthew Ahrens		    options.group or options.everyone or options.create:
35814843421SMatthew Ahrens			parser.error(_("invalid option combined with -s"))
35914843421SMatthew Ahrens		if args[0][0] != "@":
36014843421SMatthew Ahrens			parser.error(_("invalid set name: missing '@' prefix"))
36114843421SMatthew Ahrens
36214843421SMatthew Ahrens		(perms, fsname) = mungeargs(3)
36314843421SMatthew Ahrens		who = args[0]
36414843421SMatthew Ahrens	elif options.create:
36514843421SMatthew Ahrens		if options.local or options.descend or options.user or \
36614843421SMatthew Ahrens		    options.group or options.everyone or options.set:
36714843421SMatthew Ahrens			parser.error(_("invalid option combined with -c"))
36814843421SMatthew Ahrens
36914843421SMatthew Ahrens		(perms, fsname) = mungeargs(2)
37014843421SMatthew Ahrens		who = None
37114843421SMatthew Ahrens	elif options.everyone:
37214843421SMatthew Ahrens		if options.user or options.group or \
37314843421SMatthew Ahrens		    options.create or options.set:
37414843421SMatthew Ahrens			parser.error(_("invalid option combined with -e"))
37514843421SMatthew Ahrens
37614843421SMatthew Ahrens		(perms, fsname) = mungeargs(2)
37714843421SMatthew Ahrens		who = ["everyone"]
37814843421SMatthew Ahrens	else:
37914843421SMatthew Ahrens		(perms, fsname) = mungeargs(3)
38014843421SMatthew Ahrens		who = args[0].split(",")
38114843421SMatthew Ahrens
38214843421SMatthew Ahrens	if not options.local and not options.descend:
38314843421SMatthew Ahrens		options.local = True
38414843421SMatthew Ahrens		options.descend = True
38514843421SMatthew Ahrens
38614843421SMatthew Ahrens	d = args_to_perms(parser, options, who, perms)
38714843421SMatthew Ahrens
38814843421SMatthew Ahrens	ds = zfs.dataset.Dataset(fsname, snaps=False)
38914843421SMatthew Ahrens
39014843421SMatthew Ahrens	if not un and perms:
39114843421SMatthew Ahrens		for p in perms:
39214843421SMatthew Ahrens			if p[0] == "@" and not hasset(ds, p):
39314843421SMatthew Ahrens				parser.error(_("set %s is not defined") % p)
39414843421SMatthew Ahrens
39514843421SMatthew Ahrens	ds.set_fsacl(un, d)
39614843421SMatthew Ahrens	if un and options.recursive:
39714843421SMatthew Ahrens		for child in ds.descendents():
39814843421SMatthew Ahrens			child.set_fsacl(un, d)
399