diff options
Diffstat (limited to 'fs/cifs/cifsacl.c')
-rw-r--r-- | fs/cifs/cifsacl.c | 589 |
1 files changed, 493 insertions, 96 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 85d7cf7ff2c8..21de1d6d5849 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -23,76 +23,405 @@ | |||
23 | 23 | ||
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/string.h> | ||
27 | #include <linux/keyctl.h> | ||
28 | #include <linux/key-type.h> | ||
29 | #include <keys/user-type.h> | ||
26 | #include "cifspdu.h" | 30 | #include "cifspdu.h" |
27 | #include "cifsglob.h" | 31 | #include "cifsglob.h" |
28 | #include "cifsacl.h" | 32 | #include "cifsacl.h" |
29 | #include "cifsproto.h" | 33 | #include "cifsproto.h" |
30 | #include "cifs_debug.h" | 34 | #include "cifs_debug.h" |
31 | 35 | ||
32 | 36 | /* security id for everyone/world system group */ | |
33 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
34 | |||
35 | static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { | ||
36 | {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, | ||
37 | {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, | ||
38 | {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, | ||
39 | {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, | ||
40 | {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"}, | ||
41 | {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"}, | ||
42 | {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} } | ||
43 | ; | ||
44 | |||
45 | |||
46 | /* security id for everyone */ | ||
47 | static const struct cifs_sid sid_everyone = { | 37 | static const struct cifs_sid sid_everyone = { |
48 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; | 38 | 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; |
39 | /* security id for Authenticated Users system group */ | ||
40 | static const struct cifs_sid sid_authusers = { | ||
41 | 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} }; | ||
49 | /* group users */ | 42 | /* group users */ |
50 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; | 43 | static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; |
51 | 44 | ||
45 | const struct cred *root_cred; | ||
52 | 46 | ||
53 | int match_sid(struct cifs_sid *ctsid) | 47 | static void |
48 | shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem, | ||
49 | int *nr_del) | ||
54 | { | 50 | { |
55 | int i, j; | 51 | struct rb_node *node; |
56 | int num_subauth, num_sat, num_saw; | 52 | struct rb_node *tmp; |
57 | struct cifs_sid *cwsid; | 53 | struct cifs_sid_id *psidid; |
54 | |||
55 | node = rb_first(root); | ||
56 | while (node) { | ||
57 | tmp = node; | ||
58 | node = rb_next(tmp); | ||
59 | psidid = rb_entry(tmp, struct cifs_sid_id, rbnode); | ||
60 | if (nr_to_scan == 0 || *nr_del == nr_to_scan) | ||
61 | ++(*nr_rem); | ||
62 | else { | ||
63 | if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE) | ||
64 | && psidid->refcount == 0) { | ||
65 | rb_erase(tmp, root); | ||
66 | ++(*nr_del); | ||
67 | } else | ||
68 | ++(*nr_rem); | ||
69 | } | ||
70 | } | ||
71 | } | ||
58 | 72 | ||
59 | if (!ctsid) | 73 | /* |
60 | return -1; | 74 | * Run idmap cache shrinker. |
75 | */ | ||
76 | static int | ||
77 | cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc) | ||
78 | { | ||
79 | int nr_to_scan = sc->nr_to_scan; | ||
80 | int nr_del = 0; | ||
81 | int nr_rem = 0; | ||
82 | struct rb_root *root; | ||
83 | |||
84 | root = &uidtree; | ||
85 | spin_lock(&siduidlock); | ||
86 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
87 | spin_unlock(&siduidlock); | ||
88 | |||
89 | root = &gidtree; | ||
90 | spin_lock(&sidgidlock); | ||
91 | shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del); | ||
92 | spin_unlock(&sidgidlock); | ||
93 | |||
94 | return nr_rem; | ||
95 | } | ||
96 | |||
97 | static struct shrinker cifs_shrinker = { | ||
98 | .shrink = cifs_idmap_shrinker, | ||
99 | .seeks = DEFAULT_SEEKS, | ||
100 | }; | ||
61 | 101 | ||
62 | for (i = 0; i < NUM_WK_SIDS; ++i) { | 102 | static int |
63 | cwsid = &(wksidarr[i].cifssid); | 103 | cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) |
104 | { | ||
105 | char *payload; | ||
106 | |||
107 | payload = kmalloc(datalen, GFP_KERNEL); | ||
108 | if (!payload) | ||
109 | return -ENOMEM; | ||
64 | 110 | ||
65 | /* compare the revision */ | 111 | memcpy(payload, data, datalen); |
66 | if (ctsid->revision != cwsid->revision) | 112 | key->payload.data = payload; |
67 | continue; | 113 | return 0; |
114 | } | ||
68 | 115 | ||
69 | /* compare all of the six auth values */ | 116 | static inline void |
70 | for (j = 0; j < 6; ++j) { | 117 | cifs_idmap_key_destroy(struct key *key) |
71 | if (ctsid->authority[j] != cwsid->authority[j]) | 118 | { |
72 | break; | 119 | kfree(key->payload.data); |
120 | } | ||
121 | |||
122 | struct key_type cifs_idmap_key_type = { | ||
123 | .name = "cifs.idmap", | ||
124 | .instantiate = cifs_idmap_key_instantiate, | ||
125 | .destroy = cifs_idmap_key_destroy, | ||
126 | .describe = user_describe, | ||
127 | .match = user_match, | ||
128 | }; | ||
129 | |||
130 | static void | ||
131 | sid_to_str(struct cifs_sid *sidptr, char *sidstr) | ||
132 | { | ||
133 | int i; | ||
134 | unsigned long saval; | ||
135 | char *strptr; | ||
136 | |||
137 | strptr = sidstr; | ||
138 | |||
139 | sprintf(strptr, "%s", "S"); | ||
140 | strptr = sidstr + strlen(sidstr); | ||
141 | |||
142 | sprintf(strptr, "-%d", sidptr->revision); | ||
143 | strptr = sidstr + strlen(sidstr); | ||
144 | |||
145 | for (i = 0; i < 6; ++i) { | ||
146 | if (sidptr->authority[i]) { | ||
147 | sprintf(strptr, "-%d", sidptr->authority[i]); | ||
148 | strptr = sidstr + strlen(sidstr); | ||
73 | } | 149 | } |
74 | if (j < 6) | 150 | } |
75 | continue; /* all of the auth values did not match */ | 151 | |
76 | 152 | for (i = 0; i < sidptr->num_subauth; ++i) { | |
77 | /* compare all of the subauth values if any */ | 153 | saval = le32_to_cpu(sidptr->sub_auth[i]); |
78 | num_sat = ctsid->num_subauth; | 154 | sprintf(strptr, "-%ld", saval); |
79 | num_saw = cwsid->num_subauth; | 155 | strptr = sidstr + strlen(sidstr); |
80 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | 156 | } |
81 | if (num_subauth) { | 157 | } |
82 | for (j = 0; j < num_subauth; ++j) { | 158 | |
83 | if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) | 159 | static void |
84 | break; | 160 | id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr, |
85 | } | 161 | struct cifs_sid_id **psidid, char *typestr) |
86 | if (j < num_subauth) | 162 | { |
87 | continue; /* all sub_auth values do not match */ | 163 | int rc; |
164 | char *strptr; | ||
165 | struct rb_node *node = root->rb_node; | ||
166 | struct rb_node *parent = NULL; | ||
167 | struct rb_node **linkto = &(root->rb_node); | ||
168 | struct cifs_sid_id *lsidid; | ||
169 | |||
170 | while (node) { | ||
171 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
172 | parent = node; | ||
173 | rc = compare_sids(sidptr, &((lsidid)->sid)); | ||
174 | if (rc > 0) { | ||
175 | linkto = &(node->rb_left); | ||
176 | node = node->rb_left; | ||
177 | } else if (rc < 0) { | ||
178 | linkto = &(node->rb_right); | ||
179 | node = node->rb_right; | ||
88 | } | 180 | } |
181 | } | ||
182 | |||
183 | memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid)); | ||
184 | (*psidid)->time = jiffies - (SID_MAP_RETRY + 1); | ||
185 | (*psidid)->refcount = 0; | ||
186 | |||
187 | sprintf((*psidid)->sidstr, "%s", typestr); | ||
188 | strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr); | ||
189 | sid_to_str(&(*psidid)->sid, strptr); | ||
190 | |||
191 | clear_bit(SID_ID_PENDING, &(*psidid)->state); | ||
192 | clear_bit(SID_ID_MAPPED, &(*psidid)->state); | ||
193 | |||
194 | rb_link_node(&(*psidid)->rbnode, parent, linkto); | ||
195 | rb_insert_color(&(*psidid)->rbnode, root); | ||
196 | } | ||
89 | 197 | ||
90 | cFYI(1, "matching sid: %s\n", wksidarr[i].sidname); | 198 | static struct cifs_sid_id * |
91 | return 0; /* sids compare/match */ | 199 | id_rb_search(struct rb_root *root, struct cifs_sid *sidptr) |
200 | { | ||
201 | int rc; | ||
202 | struct rb_node *node = root->rb_node; | ||
203 | struct cifs_sid_id *lsidid; | ||
204 | |||
205 | while (node) { | ||
206 | lsidid = rb_entry(node, struct cifs_sid_id, rbnode); | ||
207 | rc = compare_sids(sidptr, &((lsidid)->sid)); | ||
208 | if (rc > 0) { | ||
209 | node = node->rb_left; | ||
210 | } else if (rc < 0) { | ||
211 | node = node->rb_right; | ||
212 | } else /* node found */ | ||
213 | return lsidid; | ||
92 | } | 214 | } |
93 | 215 | ||
94 | cFYI(1, "No matching sid"); | 216 | return NULL; |
95 | return -1; | 217 | } |
218 | |||
219 | static int | ||
220 | sidid_pending_wait(void *unused) | ||
221 | { | ||
222 | schedule(); | ||
223 | return signal_pending(current) ? -ERESTARTSYS : 0; | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, | ||
228 | struct cifs_fattr *fattr, uint sidtype) | ||
229 | { | ||
230 | int rc; | ||
231 | unsigned long cid; | ||
232 | struct key *idkey; | ||
233 | const struct cred *saved_cred; | ||
234 | struct cifs_sid_id *psidid, *npsidid; | ||
235 | struct rb_root *cidtree; | ||
236 | spinlock_t *cidlock; | ||
237 | |||
238 | if (sidtype == SIDOWNER) { | ||
239 | cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */ | ||
240 | cidlock = &siduidlock; | ||
241 | cidtree = &uidtree; | ||
242 | } else if (sidtype == SIDGROUP) { | ||
243 | cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */ | ||
244 | cidlock = &sidgidlock; | ||
245 | cidtree = &gidtree; | ||
246 | } else | ||
247 | return -ENOENT; | ||
248 | |||
249 | spin_lock(cidlock); | ||
250 | psidid = id_rb_search(cidtree, psid); | ||
251 | |||
252 | if (!psidid) { /* node does not exist, allocate one & attempt adding */ | ||
253 | spin_unlock(cidlock); | ||
254 | npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL); | ||
255 | if (!npsidid) | ||
256 | return -ENOMEM; | ||
257 | |||
258 | npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL); | ||
259 | if (!npsidid->sidstr) { | ||
260 | kfree(npsidid); | ||
261 | return -ENOMEM; | ||
262 | } | ||
263 | |||
264 | spin_lock(cidlock); | ||
265 | psidid = id_rb_search(cidtree, psid); | ||
266 | if (psidid) { /* node happened to get inserted meanwhile */ | ||
267 | ++psidid->refcount; | ||
268 | spin_unlock(cidlock); | ||
269 | kfree(npsidid->sidstr); | ||
270 | kfree(npsidid); | ||
271 | } else { | ||
272 | psidid = npsidid; | ||
273 | id_rb_insert(cidtree, psid, &psidid, | ||
274 | sidtype == SIDOWNER ? "os:" : "gs:"); | ||
275 | ++psidid->refcount; | ||
276 | spin_unlock(cidlock); | ||
277 | } | ||
278 | } else { | ||
279 | ++psidid->refcount; | ||
280 | spin_unlock(cidlock); | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * If we are here, it is safe to access psidid and its fields | ||
285 | * since a reference was taken earlier while holding the spinlock. | ||
286 | * A reference on the node is put without holding the spinlock | ||
287 | * and it is OK to do so in this case, shrinker will not erase | ||
288 | * this node until all references are put and we do not access | ||
289 | * any fields of the node after a reference is put . | ||
290 | */ | ||
291 | if (test_bit(SID_ID_MAPPED, &psidid->state)) { | ||
292 | cid = psidid->id; | ||
293 | psidid->time = jiffies; /* update ts for accessing */ | ||
294 | goto sid_to_id_out; | ||
295 | } | ||
296 | |||
297 | if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) | ||
298 | goto sid_to_id_out; | ||
299 | |||
300 | if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) { | ||
301 | saved_cred = override_creds(root_cred); | ||
302 | idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, ""); | ||
303 | if (IS_ERR(idkey)) | ||
304 | cFYI(1, "%s: Can't map SID to an id", __func__); | ||
305 | else { | ||
306 | cid = *(unsigned long *)idkey->payload.value; | ||
307 | psidid->id = cid; | ||
308 | set_bit(SID_ID_MAPPED, &psidid->state); | ||
309 | key_put(idkey); | ||
310 | kfree(psidid->sidstr); | ||
311 | } | ||
312 | revert_creds(saved_cred); | ||
313 | psidid->time = jiffies; /* update ts for accessing */ | ||
314 | clear_bit(SID_ID_PENDING, &psidid->state); | ||
315 | wake_up_bit(&psidid->state, SID_ID_PENDING); | ||
316 | } else { | ||
317 | rc = wait_on_bit(&psidid->state, SID_ID_PENDING, | ||
318 | sidid_pending_wait, TASK_INTERRUPTIBLE); | ||
319 | if (rc) { | ||
320 | cFYI(1, "%s: sidid_pending_wait interrupted %d", | ||
321 | __func__, rc); | ||
322 | --psidid->refcount; /* decremented without spinlock */ | ||
323 | return rc; | ||
324 | } | ||
325 | if (test_bit(SID_ID_MAPPED, &psidid->state)) | ||
326 | cid = psidid->id; | ||
327 | } | ||
328 | |||
329 | sid_to_id_out: | ||
330 | --psidid->refcount; /* decremented without spinlock */ | ||
331 | if (sidtype == SIDOWNER) | ||
332 | fattr->cf_uid = cid; | ||
333 | else | ||
334 | fattr->cf_gid = cid; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | int | ||
340 | init_cifs_idmap(void) | ||
341 | { | ||
342 | struct cred *cred; | ||
343 | struct key *keyring; | ||
344 | int ret; | ||
345 | |||
346 | cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name); | ||
347 | |||
348 | /* create an override credential set with a special thread keyring in | ||
349 | * which requests are cached | ||
350 | * | ||
351 | * this is used to prevent malicious redirections from being installed | ||
352 | * with add_key(). | ||
353 | */ | ||
354 | cred = prepare_kernel_cred(NULL); | ||
355 | if (!cred) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, | ||
359 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
360 | KEY_USR_VIEW | KEY_USR_READ, | ||
361 | KEY_ALLOC_NOT_IN_QUOTA); | ||
362 | if (IS_ERR(keyring)) { | ||
363 | ret = PTR_ERR(keyring); | ||
364 | goto failed_put_cred; | ||
365 | } | ||
366 | |||
367 | ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); | ||
368 | if (ret < 0) | ||
369 | goto failed_put_key; | ||
370 | |||
371 | ret = register_key_type(&cifs_idmap_key_type); | ||
372 | if (ret < 0) | ||
373 | goto failed_put_key; | ||
374 | |||
375 | /* instruct request_key() to use this special keyring as a cache for | ||
376 | * the results it looks up */ | ||
377 | cred->thread_keyring = keyring; | ||
378 | cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | ||
379 | root_cred = cred; | ||
380 | |||
381 | spin_lock_init(&siduidlock); | ||
382 | uidtree = RB_ROOT; | ||
383 | spin_lock_init(&sidgidlock); | ||
384 | gidtree = RB_ROOT; | ||
385 | |||
386 | register_shrinker(&cifs_shrinker); | ||
387 | |||
388 | cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring)); | ||
389 | return 0; | ||
390 | |||
391 | failed_put_key: | ||
392 | key_put(keyring); | ||
393 | failed_put_cred: | ||
394 | put_cred(cred); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | void | ||
399 | exit_cifs_idmap(void) | ||
400 | { | ||
401 | key_revoke(root_cred->thread_keyring); | ||
402 | unregister_key_type(&cifs_idmap_key_type); | ||
403 | put_cred(root_cred); | ||
404 | unregister_shrinker(&cifs_shrinker); | ||
405 | cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name); | ||
406 | } | ||
407 | |||
408 | void | ||
409 | cifs_destroy_idmaptrees(void) | ||
410 | { | ||
411 | struct rb_root *root; | ||
412 | struct rb_node *node; | ||
413 | |||
414 | root = &uidtree; | ||
415 | spin_lock(&siduidlock); | ||
416 | while ((node = rb_first(root))) | ||
417 | rb_erase(node, root); | ||
418 | spin_unlock(&siduidlock); | ||
419 | |||
420 | root = &gidtree; | ||
421 | spin_lock(&sidgidlock); | ||
422 | while ((node = rb_first(root))) | ||
423 | rb_erase(node, root); | ||
424 | spin_unlock(&sidgidlock); | ||
96 | } | 425 | } |
97 | 426 | ||
98 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are | 427 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are |
@@ -103,16 +432,24 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
103 | int num_subauth, num_sat, num_saw; | 432 | int num_subauth, num_sat, num_saw; |
104 | 433 | ||
105 | if ((!ctsid) || (!cwsid)) | 434 | if ((!ctsid) || (!cwsid)) |
106 | return 0; | 435 | return 1; |
107 | 436 | ||
108 | /* compare the revision */ | 437 | /* compare the revision */ |
109 | if (ctsid->revision != cwsid->revision) | 438 | if (ctsid->revision != cwsid->revision) { |
110 | return 0; | 439 | if (ctsid->revision > cwsid->revision) |
440 | return 1; | ||
441 | else | ||
442 | return -1; | ||
443 | } | ||
111 | 444 | ||
112 | /* compare all of the six auth values */ | 445 | /* compare all of the six auth values */ |
113 | for (i = 0; i < 6; ++i) { | 446 | for (i = 0; i < 6; ++i) { |
114 | if (ctsid->authority[i] != cwsid->authority[i]) | 447 | if (ctsid->authority[i] != cwsid->authority[i]) { |
115 | return 0; | 448 | if (ctsid->authority[i] > cwsid->authority[i]) |
449 | return 1; | ||
450 | else | ||
451 | return -1; | ||
452 | } | ||
116 | } | 453 | } |
117 | 454 | ||
118 | /* compare all of the subauth values if any */ | 455 | /* compare all of the subauth values if any */ |
@@ -121,12 +458,17 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
121 | num_subauth = num_sat < num_saw ? num_sat : num_saw; | 458 | num_subauth = num_sat < num_saw ? num_sat : num_saw; |
122 | if (num_subauth) { | 459 | if (num_subauth) { |
123 | for (i = 0; i < num_subauth; ++i) { | 460 | for (i = 0; i < num_subauth; ++i) { |
124 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) | 461 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { |
125 | return 0; | 462 | if (le32_to_cpu(ctsid->sub_auth[i]) > |
463 | le32_to_cpu(cwsid->sub_auth[i])) | ||
464 | return 1; | ||
465 | else | ||
466 | return -1; | ||
467 | } | ||
126 | } | 468 | } |
127 | } | 469 | } |
128 | 470 | ||
129 | return 1; /* sids compare/match */ | 471 | return 0; /* sids compare/match */ |
130 | } | 472 | } |
131 | 473 | ||
132 | 474 | ||
@@ -367,32 +709,42 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
367 | if (num_aces > 0) { | 709 | if (num_aces > 0) { |
368 | umode_t user_mask = S_IRWXU; | 710 | umode_t user_mask = S_IRWXU; |
369 | umode_t group_mask = S_IRWXG; | 711 | umode_t group_mask = S_IRWXG; |
370 | umode_t other_mask = S_IRWXO; | 712 | umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; |
371 | 713 | ||
372 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), | 714 | ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), |
373 | GFP_KERNEL); | 715 | GFP_KERNEL); |
716 | if (!ppace) { | ||
717 | cERROR(1, "DACL memory allocation error"); | ||
718 | return; | ||
719 | } | ||
374 | 720 | ||
375 | for (i = 0; i < num_aces; ++i) { | 721 | for (i = 0; i < num_aces; ++i) { |
376 | ppace[i] = (struct cifs_ace *) (acl_base + acl_size); | 722 | ppace[i] = (struct cifs_ace *) (acl_base + acl_size); |
377 | #ifdef CONFIG_CIFS_DEBUG2 | 723 | #ifdef CONFIG_CIFS_DEBUG2 |
378 | dump_ace(ppace[i], end_of_acl); | 724 | dump_ace(ppace[i], end_of_acl); |
379 | #endif | 725 | #endif |
380 | if (compare_sids(&(ppace[i]->sid), pownersid)) | 726 | if (compare_sids(&(ppace[i]->sid), pownersid) == 0) |
381 | access_flags_to_mode(ppace[i]->access_req, | 727 | access_flags_to_mode(ppace[i]->access_req, |
382 | ppace[i]->type, | 728 | ppace[i]->type, |
383 | &fattr->cf_mode, | 729 | &fattr->cf_mode, |
384 | &user_mask); | 730 | &user_mask); |
385 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) | 731 | if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) |
386 | access_flags_to_mode(ppace[i]->access_req, | 732 | access_flags_to_mode(ppace[i]->access_req, |
387 | ppace[i]->type, | 733 | ppace[i]->type, |
388 | &fattr->cf_mode, | 734 | &fattr->cf_mode, |
389 | &group_mask); | 735 | &group_mask); |
390 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) | 736 | if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) |
737 | access_flags_to_mode(ppace[i]->access_req, | ||
738 | ppace[i]->type, | ||
739 | &fattr->cf_mode, | ||
740 | &other_mask); | ||
741 | if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0) | ||
391 | access_flags_to_mode(ppace[i]->access_req, | 742 | access_flags_to_mode(ppace[i]->access_req, |
392 | ppace[i]->type, | 743 | ppace[i]->type, |
393 | &fattr->cf_mode, | 744 | &fattr->cf_mode, |
394 | &other_mask); | 745 | &other_mask); |
395 | 746 | ||
747 | |||
396 | /* memcpy((void *)(&(cifscred->aces[i])), | 748 | /* memcpy((void *)(&(cifscred->aces[i])), |
397 | (void *)ppace[i], | 749 | (void *)ppace[i], |
398 | sizeof(struct cifs_ace)); */ | 750 | sizeof(struct cifs_ace)); */ |
@@ -464,10 +816,10 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
464 | 816 | ||
465 | 817 | ||
466 | /* Convert CIFS ACL to POSIX form */ | 818 | /* Convert CIFS ACL to POSIX form */ |
467 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | 819 | static int parse_sec_desc(struct cifs_sb_info *cifs_sb, |
468 | struct cifs_fattr *fattr) | 820 | struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr) |
469 | { | 821 | { |
470 | int rc; | 822 | int rc = 0; |
471 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 823 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
472 | struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ | 824 | struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ |
473 | char *end_of_acl = ((char *)pntsd) + acl_len; | 825 | char *end_of_acl = ((char *)pntsd) + acl_len; |
@@ -489,12 +841,26 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
489 | le32_to_cpu(pntsd->sacloffset), dacloffset); | 841 | le32_to_cpu(pntsd->sacloffset), dacloffset); |
490 | /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ | 842 | /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ |
491 | rc = parse_sid(owner_sid_ptr, end_of_acl); | 843 | rc = parse_sid(owner_sid_ptr, end_of_acl); |
492 | if (rc) | 844 | if (rc) { |
845 | cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc); | ||
493 | return rc; | 846 | return rc; |
847 | } | ||
848 | rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER); | ||
849 | if (rc) { | ||
850 | cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc); | ||
851 | return rc; | ||
852 | } | ||
494 | 853 | ||
495 | rc = parse_sid(group_sid_ptr, end_of_acl); | 854 | rc = parse_sid(group_sid_ptr, end_of_acl); |
496 | if (rc) | 855 | if (rc) { |
856 | cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc); | ||
857 | return rc; | ||
858 | } | ||
859 | rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); | ||
860 | if (rc) { | ||
861 | cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc); | ||
497 | return rc; | 862 | return rc; |
863 | } | ||
498 | 864 | ||
499 | if (dacloffset) | 865 | if (dacloffset) |
500 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, | 866 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, |
@@ -509,7 +875,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
509 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, | 875 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, |
510 | sizeof(struct cifs_sid)); */ | 876 | sizeof(struct cifs_sid)); */ |
511 | 877 | ||
512 | return 0; | 878 | return rc; |
513 | } | 879 | } |
514 | 880 | ||
515 | 881 | ||
@@ -557,13 +923,20 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, | |||
557 | { | 923 | { |
558 | struct cifs_ntsd *pntsd = NULL; | 924 | struct cifs_ntsd *pntsd = NULL; |
559 | int xid, rc; | 925 | int xid, rc; |
926 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
927 | |||
928 | if (IS_ERR(tlink)) | ||
929 | return ERR_CAST(tlink); | ||
560 | 930 | ||
561 | xid = GetXid(); | 931 | xid = GetXid(); |
562 | rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); | 932 | rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); |
563 | FreeXid(xid); | 933 | FreeXid(xid); |
564 | 934 | ||
935 | cifs_put_tlink(tlink); | ||
565 | 936 | ||
566 | cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); | 937 | cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); |
938 | if (rc) | ||
939 | return ERR_PTR(rc); | ||
567 | return pntsd; | 940 | return pntsd; |
568 | } | 941 | } |
569 | 942 | ||
@@ -574,28 +947,34 @@ static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, | |||
574 | int oplock = 0; | 947 | int oplock = 0; |
575 | int xid, rc; | 948 | int xid, rc; |
576 | __u16 fid; | 949 | __u16 fid; |
950 | struct cifs_tcon *tcon; | ||
951 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
577 | 952 | ||
953 | if (IS_ERR(tlink)) | ||
954 | return ERR_CAST(tlink); | ||
955 | |||
956 | tcon = tlink_tcon(tlink); | ||
578 | xid = GetXid(); | 957 | xid = GetXid(); |
579 | 958 | ||
580 | rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0, | 959 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0, |
581 | &fid, &oplock, NULL, cifs_sb->local_nls, | 960 | &fid, &oplock, NULL, cifs_sb->local_nls, |
582 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 961 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
583 | if (rc) { | 962 | if (!rc) { |
584 | cERROR(1, "Unable to open file to get ACL"); | 963 | rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen); |
585 | goto out; | 964 | CIFSSMBClose(xid, tcon, fid); |
586 | } | 965 | } |
587 | 966 | ||
588 | rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen); | 967 | cifs_put_tlink(tlink); |
589 | cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen); | ||
590 | |||
591 | CIFSSMBClose(xid, cifs_sb->tcon, fid); | ||
592 | out: | ||
593 | FreeXid(xid); | 968 | FreeXid(xid); |
969 | |||
970 | cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen); | ||
971 | if (rc) | ||
972 | return ERR_PTR(rc); | ||
594 | return pntsd; | 973 | return pntsd; |
595 | } | 974 | } |
596 | 975 | ||
597 | /* Retrieve an ACL from the server */ | 976 | /* Retrieve an ACL from the server */ |
598 | static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | 977 | struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, |
599 | struct inode *inode, const char *path, | 978 | struct inode *inode, const char *path, |
600 | u32 *pacllen) | 979 | u32 *pacllen) |
601 | { | 980 | { |
@@ -603,7 +982,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, | |||
603 | struct cifsFileInfo *open_file = NULL; | 982 | struct cifsFileInfo *open_file = NULL; |
604 | 983 | ||
605 | if (inode) | 984 | if (inode) |
606 | open_file = find_readable_file(CIFS_I(inode)); | 985 | open_file = find_readable_file(CIFS_I(inode), true); |
607 | if (!open_file) | 986 | if (!open_file) |
608 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); | 987 | return get_cifs_acl_by_path(cifs_sb, path, pacllen); |
609 | 988 | ||
@@ -616,10 +995,15 @@ static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid, | |||
616 | struct cifs_ntsd *pnntsd, u32 acllen) | 995 | struct cifs_ntsd *pnntsd, u32 acllen) |
617 | { | 996 | { |
618 | int xid, rc; | 997 | int xid, rc; |
998 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
999 | |||
1000 | if (IS_ERR(tlink)) | ||
1001 | return PTR_ERR(tlink); | ||
619 | 1002 | ||
620 | xid = GetXid(); | 1003 | xid = GetXid(); |
621 | rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); | 1004 | rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen); |
622 | FreeXid(xid); | 1005 | FreeXid(xid); |
1006 | cifs_put_tlink(tlink); | ||
623 | 1007 | ||
624 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); | 1008 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); |
625 | return rc; | 1009 | return rc; |
@@ -631,10 +1015,16 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, | |||
631 | int oplock = 0; | 1015 | int oplock = 0; |
632 | int xid, rc; | 1016 | int xid, rc; |
633 | __u16 fid; | 1017 | __u16 fid; |
1018 | struct cifs_tcon *tcon; | ||
1019 | struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); | ||
1020 | |||
1021 | if (IS_ERR(tlink)) | ||
1022 | return PTR_ERR(tlink); | ||
634 | 1023 | ||
1024 | tcon = tlink_tcon(tlink); | ||
635 | xid = GetXid(); | 1025 | xid = GetXid(); |
636 | 1026 | ||
637 | rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0, | 1027 | rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0, |
638 | &fid, &oplock, NULL, cifs_sb->local_nls, | 1028 | &fid, &oplock, NULL, cifs_sb->local_nls, |
639 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 1029 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
640 | if (rc) { | 1030 | if (rc) { |
@@ -642,17 +1032,18 @@ static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path, | |||
642 | goto out; | 1032 | goto out; |
643 | } | 1033 | } |
644 | 1034 | ||
645 | rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen); | 1035 | rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen); |
646 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); | 1036 | cFYI(DBG2, "SetCIFSACL rc = %d", rc); |
647 | 1037 | ||
648 | CIFSSMBClose(xid, cifs_sb->tcon, fid); | 1038 | CIFSSMBClose(xid, tcon, fid); |
649 | out: | 1039 | out: |
650 | FreeXid(xid); | 1040 | FreeXid(xid); |
1041 | cifs_put_tlink(tlink); | ||
651 | return rc; | 1042 | return rc; |
652 | } | 1043 | } |
653 | 1044 | ||
654 | /* Set an ACL on the server */ | 1045 | /* Set an ACL on the server */ |
655 | static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | 1046 | int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, |
656 | struct inode *inode, const char *path) | 1047 | struct inode *inode, const char *path) |
657 | { | 1048 | { |
658 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1049 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
@@ -661,7 +1052,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
661 | 1052 | ||
662 | cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); | 1053 | cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode); |
663 | 1054 | ||
664 | open_file = find_readable_file(CIFS_I(inode)); | 1055 | open_file = find_readable_file(CIFS_I(inode), true); |
665 | if (!open_file) | 1056 | if (!open_file) |
666 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); | 1057 | return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen); |
667 | 1058 | ||
@@ -671,7 +1062,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
671 | } | 1062 | } |
672 | 1063 | ||
673 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 1064 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
674 | void | 1065 | int |
675 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | 1066 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, |
676 | struct inode *inode, const char *path, const __u16 *pfid) | 1067 | struct inode *inode, const char *path, const __u16 *pfid) |
677 | { | 1068 | { |
@@ -687,17 +1078,21 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, | |||
687 | pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); | 1078 | pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); |
688 | 1079 | ||
689 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ | 1080 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ |
690 | if (pntsd) | 1081 | if (IS_ERR(pntsd)) { |
691 | rc = parse_sec_desc(pntsd, acllen, fattr); | 1082 | rc = PTR_ERR(pntsd); |
692 | if (rc) | 1083 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); |
693 | cFYI(1, "parse sec desc failed rc = %d", rc); | 1084 | } else { |
1085 | rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr); | ||
1086 | kfree(pntsd); | ||
1087 | if (rc) | ||
1088 | cERROR(1, "parse sec desc failed rc = %d", rc); | ||
1089 | } | ||
694 | 1090 | ||
695 | kfree(pntsd); | 1091 | return rc; |
696 | return; | ||
697 | } | 1092 | } |
698 | 1093 | ||
699 | /* Convert mode bits to an ACL so we can update the ACL on the server */ | 1094 | /* Convert mode bits to an ACL so we can update the ACL on the server */ |
700 | int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | 1095 | int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) |
701 | { | 1096 | { |
702 | int rc = 0; | 1097 | int rc = 0; |
703 | __u32 secdesclen = 0; | 1098 | __u32 secdesclen = 0; |
@@ -712,7 +1107,10 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
712 | /* Add three ACEs for owner, group, everyone getting rid of | 1107 | /* Add three ACEs for owner, group, everyone getting rid of |
713 | other ACEs as chmod disables ACEs and set the security descriptor */ | 1108 | other ACEs as chmod disables ACEs and set the security descriptor */ |
714 | 1109 | ||
715 | if (pntsd) { | 1110 | if (IS_ERR(pntsd)) { |
1111 | rc = PTR_ERR(pntsd); | ||
1112 | cERROR(1, "%s: error %d getting sec desc", __func__, rc); | ||
1113 | } else { | ||
716 | /* allocate memory for the smb header, | 1114 | /* allocate memory for the smb header, |
717 | set security descriptor request security descriptor | 1115 | set security descriptor request security descriptor |
718 | parameters, and secuirty descriptor itself */ | 1116 | parameters, and secuirty descriptor itself */ |
@@ -742,4 +1140,3 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
742 | 1140 | ||
743 | return rc; | 1141 | return rc; |
744 | } | 1142 | } |
745 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||