5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
22 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 # Use is subject to license terms.
26 """This module implements the "zfs allow" and "zfs unallow" subcommands.
27 The only public interface is the zfs.allow.do_allow() function."""
39 class FSPerms(object):
40 """This class represents all the permissions that are set on a
41 particular filesystem (not including those inherited)."""
43 __slots__ = "create", "sets", "local", "descend", "ld"
44 __repr__ = zfs.util.default_repr
46 def __init__(self, raw):
47 """Create a FSPerms based on the dict of raw permissions
48 from zfs.ioctl.get_fsacl()."""
52 # below are { "Ntype name": set(perms) }
53 # where N is a number that we just use for sorting,
54 # type is "user", "group", "everyone", or "" (for sets)
55 # name is a user, group, or set name, or "" (for everyone)
61 # see the comment in dsl_deleg.c for the definition of whokey
62 for whokey in raw.keys():
63 perms = raw[whokey].keys()
64 whotypechr = whokey[0].lower()
67 self.create.update(perms)
68 elif whotypechr == "s":
70 self.sets.setdefault(nwho, set()).update(perms)
74 name = pwd.getpwuid(int(ws)).pw_name
77 nwho = "1user " + name
78 elif whotypechr == "g":
80 name = grp.getgrgid(int(ws)).gr_name
83 nwho = "2group " + name
84 elif whotypechr == "e":
87 raise ValueError(whotypechr)
91 elif whokey[1] == "d":
94 raise ValueError(whokey[1])
96 d.setdefault(nwho, set()).update(perms)
98 # Find perms that are in both local and descend, and
100 for nwho in self.local:
101 if nwho not in self.descend:
103 # note: these are set operations
104 self.ld[nwho] = self.local[nwho] & self.descend[nwho]
105 self.local[nwho] -= self.ld[nwho]
106 self.descend[nwho] -= self.ld[nwho]
109 def __ldstr(d, header):
111 for (nwho, perms) in sorted(d.items()):
112 # local and descend may have entries where perms
113 # is an empty set, due to consolidating all
114 # permissions into ld
117 (nwho[1:], ",".join(sorted(perms)))
123 s = self.__ldstr(self.sets, _("Permission sets:\n"))
126 s += _("Create time permissions:\n")
127 s += "\t%s\n" % ",".join(sorted(self.create))
129 s += self.__ldstr(self.local, _("Local permissions:\n"))
130 s += self.__ldstr(self.descend, _("Descendent permissions:\n"))
131 s += self.__ldstr(self.ld, _("Local+Descendent permissions:\n"))
134 def args_to_perms(parser, options, who, perms):
135 """Return a dict of raw perms {"whostr" -> {"perm" -> None}}
136 based on the command-line input."""
138 # perms is not set if we are doing a "zfs unallow <who> <fs>" to
139 # remove all of someone's permissions
141 setperms = dict(((p, None) for p in perms if p[0] == "@"))
142 baseperms = dict(((canonicalized_perm(p), None)
143 for p in perms if p[0] != "@"))
150 def storeperm(typechr, inheritchr, arg):
151 assert typechr in "ugecs"
152 assert inheritchr in "ld-"
155 return "%c%c$%s" % (t, inheritchr, arg)
157 if baseperms or not perms:
158 d[mkwhokey(typechr)] = baseperms
159 if setperms or not perms:
160 d[mkwhokey(typechr.upper())] = setperms
162 def decodeid(w, toidfunc, fmt):
167 return toidfunc(w)[2]
169 parser.error(fmt % w)
172 storeperm("s", "-", who)
174 storeperm("c", "-", "")
178 id = decodeid(w, pwd.getpwnam,
179 _("invalid user %s"))
182 id = decodeid(w, grp.getgrnam,
183 _("invalid group %s"))
185 elif w == "everyone":
190 id = pwd.getpwnam(w)[2]
194 id = grp.getgrnam(w)[2]
197 parser.error(_("invalid user/group %s") % w)
199 storeperm(typechr, "l", id)
201 storeperm(typechr, "d", id)
205 create=_("Must also have the 'mount' ability"),
206 destroy=_("Must also have the 'mount' ability"),
207 snapshot=_("Must also have the 'mount' ability"),
208 rollback=_("Must also have the 'mount' ability"),
209 clone=_("""Must also have the 'create' ability and 'mount'
210 \t\t\t\tability in the origin file system"""),
211 promote=_("""Must also have the 'mount'
212 \t\t\t\tand 'promote' ability in the origin file system"""),
213 rename=_("""Must also have the 'mount' and 'create'
214 \t\t\t\tability in the new parent"""),
215 receive=_("Must also have the 'mount' and 'create' ability"),
216 allow=_("Must also have the permission that is being\n\t\t\t\tallowed"),
217 mount=_("Allows mount/umount of ZFS datasets"),
218 share=_("Allows sharing file systems over NFS or SMB\n\t\t\t\tprotocols"),
223 userprop=_("Allows changing any user property"),
224 userquota=_("Allows accessing any userquota@... property"),
225 groupquota=_("Allows accessing any groupquota@... property"),
226 userused=_("Allows reading any userused@... property"),
227 groupused=_("Allows reading any groupused@... property"),
230 def hasset(ds, setname):
231 """Return True if the given setname (string) is defined for this
233 # It would be nice to cache the result of get_fsacl().
234 for raw in ds.get_fsacl().values():
235 for whokey in raw.keys():
236 if whokey[0].lower() == "s" and whokey[3:] == setname:
240 def canonicalized_perm(permname):
241 """Return the canonical name (string) for this permission (string).
242 Raises ZFSError if it is not a valid permission."""
243 if permname in perms_subcmd.keys() or permname in perms_other.keys():
246 return zfs.dataset.getpropobj(permname).name
248 raise zfs.util.ZFSError(errno.EINVAL, permname,
249 _("invalid permission"))
252 """Print the set of supported permissions."""
253 print(_("\nThe following permissions are supported:\n"))
254 fmt = "%-16s %-14s\t%s"
255 print(fmt % (_("NAME"), _("TYPE"), _("NOTES")))
257 for (name, note) in sorted(perms_subcmd.iteritems()):
258 print(fmt % (name, _("subcommand"), note))
260 for (name, note) in sorted(perms_other.iteritems()):
261 print(fmt % (name, _("other"), note))
263 for (name, prop) in sorted(zfs.dataset.proptable.iteritems()):
264 if prop.visible and prop.delegatable():
265 print(fmt % (name, _("property"), ""))
268 """Implementes the "zfs allow" and "zfs unallow" subcommands."""
269 un = (sys.argv[1] == "unallow")
276 parser.exit("zfs: error: " + msg)
281 u = _("""unallow [-rldug] <"everyone"|user|group>[,...]
282 [<perm|@setname>[,...]] <filesystem|volume>
283 unallow [-rld] -e [<perm|@setname>[,...]] <filesystem|volume>
284 unallow [-r] -c [<perm|@setname>[,...]] <filesystem|volume>
285 unallow [-r] -s @setname [<perm|@setname>[,...]] <filesystem|volume>""")
287 sstr = _("undefine permission set")
289 u = _("""allow <filesystem|volume>
290 allow [-ldug] <"everyone"|user|group>[,...] <perm|@setname>[,...]
292 allow [-ld] -e <perm|@setname>[,...] <filesystem|volume>
293 allow -c <perm|@setname>[,...] <filesystem|volume>
294 allow -s @setname <perm|@setname>[,...] <filesystem|volume>""")
296 sstr = _("define permission set")
298 parser = optparse.OptionParser(usage=u, prog="zfs")
300 parser.add_option("-l", action="store_true", dest="local",
301 help=_("%s permission locally") % verb)
302 parser.add_option("-d", action="store_true", dest="descend",
303 help=_("%s permission for descendents") % verb)
304 parser.add_option("-u", action="store_true", dest="user",
305 help=_("%s permission for user") % verb)
306 parser.add_option("-g", action="store_true", dest="group",
307 help=_("%s permission for group") % verb)
308 parser.add_option("-e", action="store_true", dest="everyone",
309 help=_("%s permission for everyone") % verb)
310 parser.add_option("-c", action="store_true", dest="create",
311 help=_("%s create time permissions") % verb)
312 parser.add_option("-s", action="store_true", dest="set", help=sstr)
314 parser.add_option("-r", action="store_true", dest="recursive",
315 help=_("remove permissions recursively"))
317 if len(sys.argv) == 3 and not un:
318 # just print the permissions on this fs
320 if sys.argv[2] == "-h":
321 # hack to make "zfs allow -h" work
323 ds = zfs.dataset.Dataset(sys.argv[2])
326 for (fs, raw) in ds.get_fsacl().items():
329 for fs in sorted(p.keys(), reverse=True):
330 s = _("---- Permissions on %s ") % fs
331 print(s + "-" * (70-len(s)))
336 (options, args) = parser.parse_args(sys.argv[2:])
338 if sum((bool(options.everyone), bool(options.user),
339 bool(options.group))) > 1:
340 parser.error(_("-u, -g, and -e are mutually exclusive"))
342 def mungeargs(expected_len):
343 if un and len(args) == expected_len-1:
344 return (None, args[expected_len-2])
345 elif len(args) == expected_len:
346 return (args[expected_len-2].split(","),
347 args[expected_len-1])
349 usage(_("wrong number of parameters"))
352 if options.local or options.descend or options.user or \
353 options.group or options.everyone or options.create:
354 parser.error(_("invalid option combined with -s"))
355 if args[0][0] != "@":
356 parser.error(_("invalid set name: missing '@' prefix"))
358 (perms, fsname) = mungeargs(3)
361 if options.local or options.descend or options.user or \
362 options.group or options.everyone or options.set:
363 parser.error(_("invalid option combined with -c"))
365 (perms, fsname) = mungeargs(2)
367 elif options.everyone:
368 if options.user or options.group or \
369 options.create or options.set:
370 parser.error(_("invalid option combined with -e"))
372 (perms, fsname) = mungeargs(2)
375 (perms, fsname) = mungeargs(3)
376 who = args[0].split(",")
378 if not options.local and not options.descend:
380 options.descend = True
382 d = args_to_perms(parser, options, who, perms)
384 ds = zfs.dataset.Dataset(fsname, snaps=False)
388 if p[0] == "@" and not hasset(ds, p):
389 parser.error(_("set %s is not defined") % p)
392 if un and options.recursive:
393 for child in ds.descendents():
394 child.set_fsacl(un, d)