1 | /* |
2 | * CDDL HEADER START |
3 | * |
4 | * The contents of this file are subject to the terms of the |
5 | * Common Development and Distribution License (the "License"). |
6 | * You may not use this file except in compliance with the License. |
7 | * |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
9 | * or http://www.opensolaris.org/os/licensing. |
10 | * See the License for the specific language governing permissions |
11 | * and limitations under the License. |
12 | * |
13 | * When distributing Covered Code, include this CDDL HEADER in each |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
15 | * If applicable, add the following below this CDDL HEADER, with the |
16 | * fields enclosed by brackets "[]" replaced with your own identifying |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] |
18 | * |
19 | * CDDL HEADER END |
20 | */ |
21 | /* |
22 | * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. |
23 | * Copyright 2010 Nexenta Systems, Inc. All rights reserved. |
24 | * Copyright (c) 2013 by Delphix. All rights reserved. |
25 | * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> |
26 | */ |
27 | |
28 | #include <sys/zfs_context.h> |
29 | |
30 | #if defined(_KERNEL) |
31 | #include <sys/systm.h> |
32 | #include <sys/sunddi.h> |
33 | #include <sys/ctype.h> |
34 | #else |
35 | #include <stdio.h> |
36 | #include <unistd.h> |
37 | #include <strings.h> |
38 | #include <libnvpair.h> |
39 | #include <ctype.h> |
40 | #endif |
41 | #include <sys/dsl_deleg.h> |
42 | #include "zfs_prop.h" |
43 | #include "zfs_deleg.h" |
44 | #include "zfs_namecheck.h" |
45 | |
46 | zfs_deleg_perm_tab_t zfs_deleg_perm_tab[] = { |
47 | {ZFS_DELEG_PERM_ALLOW}, |
48 | {ZFS_DELEG_PERM_BOOKMARK}, |
49 | {ZFS_DELEG_PERM_CLONE}, |
50 | {ZFS_DELEG_PERM_CREATE}, |
51 | {ZFS_DELEG_PERM_DESTROY}, |
52 | {ZFS_DELEG_PERM_DIFF}, |
53 | {ZFS_DELEG_PERM_MOUNT}, |
54 | {ZFS_DELEG_PERM_PROMOTE}, |
55 | {ZFS_DELEG_PERM_RECEIVE}, |
56 | {ZFS_DELEG_PERM_RENAME}, |
57 | {ZFS_DELEG_PERM_ROLLBACK}, |
58 | {ZFS_DELEG_PERM_SNAPSHOT}, |
59 | {ZFS_DELEG_PERM_SHARE}, |
60 | {ZFS_DELEG_PERM_SEND}, |
61 | {ZFS_DELEG_PERM_USERPROP}, |
62 | {ZFS_DELEG_PERM_USERQUOTA}, |
63 | {ZFS_DELEG_PERM_GROUPQUOTA}, |
64 | {ZFS_DELEG_PERM_USERUSED}, |
65 | {ZFS_DELEG_PERM_GROUPUSED}, |
66 | {ZFS_DELEG_PERM_HOLD}, |
67 | {ZFS_DELEG_PERM_RELEASE}, |
68 | {NULL} |
69 | }; |
70 | |
71 | static int |
72 | zfs_valid_permission_name(const char *perm) |
73 | { |
74 | if (zfs_deleg_canonicalize_perm(perm)) |
75 | return (0); |
76 | |
77 | return (permset_namecheck(perm, NULL, NULL)); |
78 | } |
79 | |
80 | const char * |
81 | zfs_deleg_canonicalize_perm(const char *perm) |
82 | { |
83 | int i; |
84 | zfs_prop_t prop; |
85 | |
86 | for (i = 0; zfs_deleg_perm_tab[i].z_perm != NULL; i++) { |
87 | if (strcmp(perm, zfs_deleg_perm_tab[i].z_perm) == 0) |
88 | return (perm); |
89 | } |
90 | |
91 | prop = zfs_name_to_prop(perm); |
92 | if (prop != ZPROP_INVAL && zfs_prop_delegatable(prop)) |
93 | return (zfs_prop_to_name(prop)); |
94 | return (NULL); |
95 | |
96 | } |
97 | |
98 | static int |
99 | zfs_validate_who(char *who) |
100 | { |
101 | char *p; |
102 | |
103 | if (who[2] != ZFS_DELEG_FIELD_SEP_CHR) |
104 | return (-1); |
105 | |
106 | switch (who[0]) { |
107 | case ZFS_DELEG_USER: |
108 | case ZFS_DELEG_GROUP: |
109 | case ZFS_DELEG_USER_SETS: |
110 | case ZFS_DELEG_GROUP_SETS: |
111 | if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT) |
112 | return (-1); |
113 | for (p = &who[3]; *p; p++) |
114 | if (!isdigit(*p)) |
115 | return (-1); |
116 | break; |
117 | |
118 | case ZFS_DELEG_NAMED_SET: |
119 | case ZFS_DELEG_NAMED_SET_SETS: |
120 | if (who[1] != ZFS_DELEG_NA) |
121 | return (-1); |
122 | return (permset_namecheck(&who[3], NULL, NULL)); |
123 | |
124 | case ZFS_DELEG_CREATE: |
125 | case ZFS_DELEG_CREATE_SETS: |
126 | if (who[1] != ZFS_DELEG_NA) |
127 | return (-1); |
128 | if (who[3] != '\0') |
129 | return (-1); |
130 | break; |
131 | |
132 | case ZFS_DELEG_EVERYONE: |
133 | case ZFS_DELEG_EVERYONE_SETS: |
134 | if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT) |
135 | return (-1); |
136 | if (who[3] != '\0') |
137 | return (-1); |
138 | break; |
139 | |
140 | default: |
141 | return (-1); |
142 | } |
143 | |
144 | return (0); |
145 | } |
146 | |
147 | int |
148 | zfs_deleg_verify_nvlist(nvlist_t *nvp) |
149 | { |
150 | nvpair_t *who, *perm_name; |
151 | nvlist_t *perms; |
152 | int error; |
153 | |
154 | if (nvp == NULL) |
155 | return (-1); |
156 | |
157 | who = nvlist_next_nvpair(nvp, NULL); |
158 | if (who == NULL) |
159 | return (-1); |
160 | |
161 | do { |
162 | if (zfs_validate_who(nvpair_name(who))) |
163 | return (-1); |
164 | |
165 | error = nvlist_lookup_nvlist(nvp, nvpair_name(who), &perms); |
166 | |
167 | if (error && error != ENOENT) |
168 | return (-1); |
169 | if (error == ENOENT) |
170 | continue; |
171 | |
172 | perm_name = nvlist_next_nvpair(perms, NULL); |
173 | if (perm_name == NULL) { |
174 | return (-1); |
175 | } |
176 | do { |
177 | error = zfs_valid_permission_name( |
178 | nvpair_name(perm_name)); |
179 | if (error) |
180 | return (-1); |
181 | } while ((perm_name = nvlist_next_nvpair(perms, perm_name)) |
182 | != NULL); |
183 | } while ((who = nvlist_next_nvpair(nvp, who)) != NULL); |
184 | return (0); |
185 | } |
186 | |
187 | /* |
188 | * Construct the base attribute name. The base attribute names |
189 | * are the "key" to locate the jump objects which contain the actual |
190 | * permissions. The base attribute names are encoded based on |
191 | * type of entry and whether it is a local or descendent permission. |
192 | * |
193 | * Arguments: |
194 | * attr - attribute name return string, attribute is assumed to be |
195 | * ZFS_MAX_DELEG_NAME long. |
196 | * type - type of entry to construct |
197 | * inheritchr - inheritance type (local,descendent, or NA for create and |
198 | * permission set definitions |
199 | * data - is either a permission set name or a 64 bit uid/gid. |
200 | */ |
201 | void |
202 | zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type, |
203 | char inheritchr, void *data) |
204 | { |
205 | int len = ZFS_MAX_DELEG_NAME; |
206 | uint64_t *id = data; |
207 | |
208 | switch (type) { |
209 | case ZFS_DELEG_USER: |
210 | case ZFS_DELEG_GROUP: |
211 | case ZFS_DELEG_USER_SETS: |
212 | case ZFS_DELEG_GROUP_SETS: |
213 | (void) snprintf(attr, len, "%c%c%c%lld" , type, inheritchr, |
214 | ZFS_DELEG_FIELD_SEP_CHR, (longlong_t)*id); |
215 | break; |
216 | case ZFS_DELEG_NAMED_SET_SETS: |
217 | case ZFS_DELEG_NAMED_SET: |
218 | (void) snprintf(attr, len, "%c-%c%s" , type, |
219 | ZFS_DELEG_FIELD_SEP_CHR, (char *)data); |
220 | break; |
221 | case ZFS_DELEG_CREATE: |
222 | case ZFS_DELEG_CREATE_SETS: |
223 | (void) snprintf(attr, len, "%c-%c" , type, |
224 | ZFS_DELEG_FIELD_SEP_CHR); |
225 | break; |
226 | case ZFS_DELEG_EVERYONE: |
227 | case ZFS_DELEG_EVERYONE_SETS: |
228 | (void) snprintf(attr, len, "%c%c%c" , type, inheritchr, |
229 | ZFS_DELEG_FIELD_SEP_CHR); |
230 | break; |
231 | default: |
232 | ASSERT(!"bad zfs_deleg_who_type_t" ); |
233 | } |
234 | } |
235 | |