cifs: Add idmap key and related data structures and functions (try #17 repost)
[linux-2.6-block.git] / fs / cifs / cifsacl.c
CommitLineData
bcb02034
SF
1/*
2 * fs/cifs/cifsacl.c
3 *
8b1327f6 4 * Copyright (C) International Business Machines Corp., 2007,2008
bcb02034
SF
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
65874007 24#include <linux/fs.h>
5a0e3ad6 25#include <linux/slab.h>
4d79dba0
SP
26#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
65874007
SF
30#include "cifspdu.h"
31#include "cifsglob.h"
d0d66c44 32#include "cifsacl.h"
65874007
SF
33#include "cifsproto.h"
34#include "cifs_debug.h"
65874007 35
297647c2 36
af6f4612 37static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
297647c2
SF
38 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
39 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
536abdb0
JL
40 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
41 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
42 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
43 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
44 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
44093ca2 45;
297647c2
SF
46
47
2fbc2f17 48/* security id for everyone/world system group */
e01b6400
SP
49static const struct cifs_sid sid_everyone = {
50 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
2fbc2f17
SP
51/* security id for Authenticated Users system group */
52static const struct cifs_sid sid_authusers = {
53 1, 1, {0, 0, 0, 0, 0, 5}, {11} };
bcb02034 54/* group users */
ad7a2926 55static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 56
4d79dba0
SP
57static const struct cred *root_cred;
58
59/*
60 * Run idmap cache shrinker.
61 */
62static int
63cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
64{
65 /* Use a pruning scheme in a subsequent patch instead */
66 cifs_destroy_idmaptrees();
67 return 0;
68}
69
70static struct shrinker cifs_shrinker = {
71 .shrink = cifs_idmap_shrinker,
72 .seeks = DEFAULT_SEEKS,
73};
74
75static int
76cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
77{
78 char *payload;
79
80 payload = kmalloc(datalen, GFP_KERNEL);
81 if (!payload)
82 return -ENOMEM;
83
84 memcpy(payload, data, datalen);
85 key->payload.data = payload;
86 return 0;
87}
88
89static inline void
90cifs_idmap_key_destroy(struct key *key)
91{
92 kfree(key->payload.data);
93}
94
95static
96struct key_type cifs_idmap_key_type = {
97 .name = "cifs.cifs_idmap",
98 .instantiate = cifs_idmap_key_instantiate,
99 .destroy = cifs_idmap_key_destroy,
100 .describe = user_describe,
101 .match = user_match,
102};
103
104int
105init_cifs_idmap(void)
106{
107 struct cred *cred;
108 struct key *keyring;
109 int ret;
110
111 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
112
113 /* create an override credential set with a special thread keyring in
114 * which requests are cached
115 *
116 * this is used to prevent malicious redirections from being installed
117 * with add_key().
118 */
119 cred = prepare_kernel_cred(NULL);
120 if (!cred)
121 return -ENOMEM;
122
123 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
124 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
125 KEY_USR_VIEW | KEY_USR_READ,
126 KEY_ALLOC_NOT_IN_QUOTA);
127 if (IS_ERR(keyring)) {
128 ret = PTR_ERR(keyring);
129 goto failed_put_cred;
130 }
131
132 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
133 if (ret < 0)
134 goto failed_put_key;
135
136 ret = register_key_type(&cifs_idmap_key_type);
137 if (ret < 0)
138 goto failed_put_key;
139
140 /* instruct request_key() to use this special keyring as a cache for
141 * the results it looks up */
142 cred->thread_keyring = keyring;
143 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
144 root_cred = cred;
145
146 spin_lock_init(&siduidlock);
147 uidtree = RB_ROOT;
148 spin_lock_init(&sidgidlock);
149 gidtree = RB_ROOT;
150
151 register_shrinker(&cifs_shrinker);
152
153 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
154 return 0;
155
156failed_put_key:
157 key_put(keyring);
158failed_put_cred:
159 put_cred(cred);
160 return ret;
161}
162
163void
164exit_cifs_idmap(void)
165{
166 key_revoke(root_cred->thread_keyring);
167 unregister_key_type(&cifs_idmap_key_type);
168 put_cred(root_cred);
169 unregister_shrinker(&cifs_shrinker);
170 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
171}
172
173void
174cifs_destroy_idmaptrees(void)
175{
176 struct rb_root *root;
177 struct rb_node *node;
178
179 root = &uidtree;
180 spin_lock(&siduidlock);
181 while ((node = rb_first(root)))
182 rb_erase(node, root);
183 spin_unlock(&siduidlock);
184
185 root = &gidtree;
186 spin_lock(&sidgidlock);
187 while ((node = rb_first(root)))
188 rb_erase(node, root);
189 spin_unlock(&sidgidlock);
190}
297647c2
SF
191
192int match_sid(struct cifs_sid *ctsid)
193{
194 int i, j;
195 int num_subauth, num_sat, num_saw;
196 struct cifs_sid *cwsid;
197
198 if (!ctsid)
ef571cad 199 return -1;
297647c2
SF
200
201 for (i = 0; i < NUM_WK_SIDS; ++i) {
202 cwsid = &(wksidarr[i].cifssid);
203
204 /* compare the revision */
205 if (ctsid->revision != cwsid->revision)
206 continue;
207
208 /* compare all of the six auth values */
209 for (j = 0; j < 6; ++j) {
210 if (ctsid->authority[j] != cwsid->authority[j])
211 break;
212 }
213 if (j < 6)
214 continue; /* all of the auth values did not match */
215
216 /* compare all of the subauth values if any */
ce51ae14
DK
217 num_sat = ctsid->num_subauth;
218 num_saw = cwsid->num_subauth;
297647c2
SF
219 num_subauth = num_sat < num_saw ? num_sat : num_saw;
220 if (num_subauth) {
221 for (j = 0; j < num_subauth; ++j) {
222 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
223 break;
224 }
225 if (j < num_subauth)
226 continue; /* all sub_auth values do not match */
227 }
228
b6b38f70 229 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
ef571cad 230 return 0; /* sids compare/match */
297647c2
SF
231 }
232
b6b38f70 233 cFYI(1, "No matching sid");
ef571cad 234 return -1;
297647c2
SF
235}
236
a750e77c
SF
237/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
238 the same returns 1, if they do not match returns 0 */
630f3f0c 239int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
297647c2
SF
240{
241 int i;
242 int num_subauth, num_sat, num_saw;
243
244 if ((!ctsid) || (!cwsid))
ef571cad 245 return 0;
297647c2
SF
246
247 /* compare the revision */
248 if (ctsid->revision != cwsid->revision)
ef571cad 249 return 0;
297647c2
SF
250
251 /* compare all of the six auth values */
252 for (i = 0; i < 6; ++i) {
253 if (ctsid->authority[i] != cwsid->authority[i])
ef571cad 254 return 0;
297647c2
SF
255 }
256
257 /* compare all of the subauth values if any */
adbc0358 258 num_sat = ctsid->num_subauth;
adddd49d 259 num_saw = cwsid->num_subauth;
297647c2
SF
260 num_subauth = num_sat < num_saw ? num_sat : num_saw;
261 if (num_subauth) {
262 for (i = 0; i < num_subauth; ++i) {
263 if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
ef571cad 264 return 0;
297647c2
SF
265 }
266 }
267
ef571cad 268 return 1; /* sids compare/match */
297647c2
SF
269}
270
97837582
SF
271
272/* copy ntsd, owner sid, and group sid from a security descriptor to another */
273static void copy_sec_desc(const struct cifs_ntsd *pntsd,
274 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
275{
276 int i;
277
278 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
279 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
280
281 /* copy security descriptor control portion */
282 pnntsd->revision = pntsd->revision;
283 pnntsd->type = pntsd->type;
284 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
285 pnntsd->sacloffset = 0;
286 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
287 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
288
289 /* copy owner sid */
290 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
291 le32_to_cpu(pntsd->osidoffset));
292 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
293
294 nowner_sid_ptr->revision = owner_sid_ptr->revision;
295 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
296 for (i = 0; i < 6; i++)
297 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
298 for (i = 0; i < 5; i++)
299 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
300
301 /* copy group sid */
302 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
303 le32_to_cpu(pntsd->gsidoffset));
304 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
305 sizeof(struct cifs_sid));
306
307 ngroup_sid_ptr->revision = group_sid_ptr->revision;
308 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
309 for (i = 0; i < 6; i++)
310 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
311 for (i = 0; i < 5; i++)
b1910ad6 312 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
97837582
SF
313
314 return;
315}
316
317
630f3f0c
SF
318/*
319 change posix mode to reflect permissions
320 pmode is the existing mode (we only want to overwrite part of this
321 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
322*/
9b5e6857 323static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
15b03959 324 umode_t *pbits_to_set)
630f3f0c 325{
9b5e6857 326 __u32 flags = le32_to_cpu(ace_flags);
15b03959 327 /* the order of ACEs is important. The canonical order is to begin with
ce06c9f0 328 DENY entries followed by ALLOW, otherwise an allow entry could be
15b03959 329 encountered first, making the subsequent deny entry like "dead code"
ce06c9f0 330 which would be superflous since Windows stops when a match is made
15b03959
SF
331 for the operation you are trying to perform for your user */
332
333 /* For deny ACEs we change the mask so that subsequent allow access
334 control entries do not turn on the bits we are denying */
335 if (type == ACCESS_DENIED) {
ad7a2926 336 if (flags & GENERIC_ALL)
15b03959 337 *pbits_to_set &= ~S_IRWXUGO;
ad7a2926 338
9b5e6857
AV
339 if ((flags & GENERIC_WRITE) ||
340 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 341 *pbits_to_set &= ~S_IWUGO;
9b5e6857
AV
342 if ((flags & GENERIC_READ) ||
343 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 344 *pbits_to_set &= ~S_IRUGO;
9b5e6857
AV
345 if ((flags & GENERIC_EXECUTE) ||
346 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959
SF
347 *pbits_to_set &= ~S_IXUGO;
348 return;
349 } else if (type != ACCESS_ALLOWED) {
b6b38f70 350 cERROR(1, "unknown access control type %d", type);
15b03959
SF
351 return;
352 }
353 /* else ACCESS_ALLOWED type */
630f3f0c 354
9b5e6857 355 if (flags & GENERIC_ALL) {
15b03959 356 *pmode |= (S_IRWXUGO & (*pbits_to_set));
b6b38f70 357 cFYI(DBG2, "all perms");
d61e5808
SF
358 return;
359 }
9b5e6857
AV
360 if ((flags & GENERIC_WRITE) ||
361 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 362 *pmode |= (S_IWUGO & (*pbits_to_set));
9b5e6857
AV
363 if ((flags & GENERIC_READ) ||
364 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 365 *pmode |= (S_IRUGO & (*pbits_to_set));
9b5e6857
AV
366 if ((flags & GENERIC_EXECUTE) ||
367 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 368 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 369
b6b38f70 370 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
630f3f0c
SF
371 return;
372}
373
ce06c9f0
SF
374/*
375 Generate access flags to reflect permissions mode is the existing mode.
376 This function is called for every ACE in the DACL whose SID matches
377 with either owner or group or everyone.
378*/
379
380static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
381 __u32 *pace_flags)
382{
383 /* reset access mask */
384 *pace_flags = 0x0;
385
386 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
387 mode &= bits_to_use;
388
389 /* check for R/W/X UGO since we do not know whose flags
390 is this but we have cleared all the bits sans RWX for
391 either user or group or other as per bits_to_use */
392 if (mode & S_IRUGO)
393 *pace_flags |= SET_FILE_READ_RIGHTS;
394 if (mode & S_IWUGO)
395 *pace_flags |= SET_FILE_WRITE_RIGHTS;
396 if (mode & S_IXUGO)
397 *pace_flags |= SET_FILE_EXEC_RIGHTS;
398
b6b38f70 399 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
ce06c9f0
SF
400 return;
401}
402
2b210adc 403static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
97837582
SF
404 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
405{
406 int i;
407 __u16 size = 0;
408 __u32 access_req = 0;
409
410 pntace->type = ACCESS_ALLOWED;
411 pntace->flags = 0x0;
412 mode_to_access_flags(nmode, bits, &access_req);
413 if (!access_req)
414 access_req = SET_MINIMUM_RIGHTS;
415 pntace->access_req = cpu_to_le32(access_req);
416
417 pntace->sid.revision = psid->revision;
418 pntace->sid.num_subauth = psid->num_subauth;
419 for (i = 0; i < 6; i++)
420 pntace->sid.authority[i] = psid->authority[i];
421 for (i = 0; i < psid->num_subauth; i++)
422 pntace->sid.sub_auth[i] = psid->sub_auth[i];
423
424 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
425 pntace->size = cpu_to_le16(size);
426
ef571cad 427 return size;
97837582
SF
428}
429
297647c2 430
953f8681
SF
431#ifdef CONFIG_CIFS_DEBUG2
432static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 433{
d0d66c44 434 int num_subauth;
d0d66c44
SP
435
436 /* validate that we do not go past end of acl */
297647c2 437
44093ca2 438 if (le16_to_cpu(pace->size) < 16) {
b6b38f70 439 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
44093ca2
SF
440 return;
441 }
442
443 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
b6b38f70 444 cERROR(1, "ACL too small to parse ACE");
d0d66c44 445 return;
44093ca2 446 }
d0d66c44 447
44093ca2 448 num_subauth = pace->sid.num_subauth;
d0d66c44 449 if (num_subauth) {
8f18c131 450 int i;
b6b38f70 451 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
44093ca2 452 pace->sid.revision, pace->sid.num_subauth, pace->type,
b6b38f70 453 pace->flags, le16_to_cpu(pace->size));
d12fd121 454 for (i = 0; i < num_subauth; ++i) {
b6b38f70
JP
455 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
456 le32_to_cpu(pace->sid.sub_auth[i]));
d12fd121
SF
457 }
458
459 /* BB add length check to make sure that we do not have huge
460 num auths and therefore go off the end */
d12fd121
SF
461 }
462
463 return;
464}
953f8681 465#endif
d12fd121 466
d0d66c44 467
a750e77c 468static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 469 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
0b8f18e3 470 struct cifs_fattr *fattr)
d0d66c44
SP
471{
472 int i;
473 int num_aces = 0;
474 int acl_size;
475 char *acl_base;
d0d66c44
SP
476 struct cifs_ace **ppace;
477
478 /* BB need to add parm so we can store the SID BB */
479
2b83457b
SF
480 if (!pdacl) {
481 /* no DACL in the security descriptor, set
482 all the permissions for user/group/other */
0b8f18e3 483 fattr->cf_mode |= S_IRWXUGO;
2b83457b
SF
484 return;
485 }
486
d0d66c44 487 /* validate that we do not go past end of acl */
af6f4612 488 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
b6b38f70 489 cERROR(1, "ACL too small to parse DACL");
d0d66c44
SP
490 return;
491 }
492
b6b38f70 493 cFYI(DBG2, "DACL revision %d size %d num aces %d",
af6f4612 494 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
b6b38f70 495 le32_to_cpu(pdacl->num_aces));
d0d66c44 496
7505e052
SF
497 /* reset rwx permissions for user/group/other.
498 Also, if num_aces is 0 i.e. DACL has no ACEs,
499 user/group/other have no permissions */
0b8f18e3 500 fattr->cf_mode &= ~(S_IRWXUGO);
7505e052 501
d0d66c44
SP
502 acl_base = (char *)pdacl;
503 acl_size = sizeof(struct cifs_acl);
504
adbc0358 505 num_aces = le32_to_cpu(pdacl->num_aces);
d0d66c44 506 if (num_aces > 0) {
15b03959
SF
507 umode_t user_mask = S_IRWXU;
508 umode_t group_mask = S_IRWXG;
2fbc2f17 509 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
15b03959 510
d0d66c44
SP
511 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
512 GFP_KERNEL);
8132b65b
SF
513 if (!ppace) {
514 cERROR(1, "DACL memory allocation error");
515 return;
516 }
d0d66c44 517
d0d66c44 518 for (i = 0; i < num_aces; ++i) {
44093ca2 519 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
520#ifdef CONFIG_CIFS_DEBUG2
521 dump_ace(ppace[i], end_of_acl);
522#endif
e01b6400
SP
523 if (compare_sids(&(ppace[i]->sid), pownersid))
524 access_flags_to_mode(ppace[i]->access_req,
15b03959 525 ppace[i]->type,
0b8f18e3 526 &fattr->cf_mode,
15b03959 527 &user_mask);
e01b6400
SP
528 if (compare_sids(&(ppace[i]->sid), pgrpsid))
529 access_flags_to_mode(ppace[i]->access_req,
15b03959 530 ppace[i]->type,
0b8f18e3 531 &fattr->cf_mode,
15b03959 532 &group_mask);
e01b6400
SP
533 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
534 access_flags_to_mode(ppace[i]->access_req,
15b03959 535 ppace[i]->type,
0b8f18e3 536 &fattr->cf_mode,
15b03959 537 &other_mask);
2fbc2f17
SP
538 if (compare_sids(&(ppace[i]->sid), &sid_authusers))
539 access_flags_to_mode(ppace[i]->access_req,
540 ppace[i]->type,
541 &fattr->cf_mode,
542 &other_mask);
543
e01b6400 544
44093ca2 545/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
546 (void *)ppace[i],
547 sizeof(struct cifs_ace)); */
d0d66c44 548
44093ca2
SF
549 acl_base = (char *)ppace[i];
550 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
551 }
552
553 kfree(ppace);
d0d66c44
SP
554 }
555
556 return;
557}
558
bcb02034 559
97837582
SF
560static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
561 struct cifs_sid *pgrpsid, __u64 nmode)
562{
2b210adc 563 u16 size = 0;
97837582
SF
564 struct cifs_acl *pnndacl;
565
566 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
567
568 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
569 pownersid, nmode, S_IRWXU);
570 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
571 pgrpsid, nmode, S_IRWXG);
572 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
573 &sid_everyone, nmode, S_IRWXO);
574
575 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
d9f382ef 576 pndacl->num_aces = cpu_to_le32(3);
97837582 577
ef571cad 578 return 0;
97837582
SF
579}
580
581
bcb02034
SF
582static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
583{
584 /* BB need to add parm so we can store the SID BB */
585
b9c7a2bb
SF
586 /* validate that we do not go past end of ACL - sid must be at least 8
587 bytes long (assuming no sub-auths - e.g. the null SID */
588 if (end_of_acl < (char *)psid + 8) {
b6b38f70 589 cERROR(1, "ACL too small to parse SID %p", psid);
bcb02034
SF
590 return -EINVAL;
591 }
d0d66c44 592
af6f4612 593 if (psid->num_subauth) {
bcb02034 594#ifdef CONFIG_CIFS_DEBUG2
8f18c131 595 int i;
b6b38f70
JP
596 cFYI(1, "SID revision %d num_auth %d",
597 psid->revision, psid->num_subauth);
bcb02034 598
af6f4612 599 for (i = 0; i < psid->num_subauth; i++) {
b6b38f70
JP
600 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
601 le32_to_cpu(psid->sub_auth[i]));
d0d66c44
SP
602 }
603
d12fd121 604 /* BB add length check to make sure that we do not have huge
d0d66c44 605 num auths and therefore go off the end */
b6b38f70
JP
606 cFYI(1, "RID 0x%x",
607 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
bcb02034 608#endif
d0d66c44
SP
609 }
610
bcb02034
SF
611 return 0;
612}
613
d0d66c44 614
bcb02034 615/* Convert CIFS ACL to POSIX form */
630f3f0c 616static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
0b8f18e3 617 struct cifs_fattr *fattr)
bcb02034 618{
d0d66c44 619 int rc;
bcb02034
SF
620 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
621 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 622 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 623 __u32 dacloffset;
bcb02034 624
0b8f18e3 625 if (pntsd == NULL)
b9c7a2bb
SF
626 return -EIO;
627
bcb02034 628 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 629 le32_to_cpu(pntsd->osidoffset));
bcb02034 630 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 631 le32_to_cpu(pntsd->gsidoffset));
7505e052 632 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 633 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
b6b38f70 634 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
bcb02034 635 "sacloffset 0x%x dacloffset 0x%x",
af6f4612
SF
636 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
637 le32_to_cpu(pntsd->gsidoffset),
b6b38f70 638 le32_to_cpu(pntsd->sacloffset), dacloffset);
b9c7a2bb 639/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034
SF
640 rc = parse_sid(owner_sid_ptr, end_of_acl);
641 if (rc)
642 return rc;
643
644 rc = parse_sid(group_sid_ptr, end_of_acl);
645 if (rc)
646 return rc;
647
7505e052
SF
648 if (dacloffset)
649 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
0b8f18e3 650 group_sid_ptr, fattr);
7505e052 651 else
b6b38f70 652 cFYI(1, "no ACL"); /* BB grant all or default perms? */
d0d66c44 653
bcb02034
SF
654/* cifscred->uid = owner_sid_ptr->rid;
655 cifscred->gid = group_sid_ptr->rid;
656 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
630f3f0c 657 sizeof(struct cifs_sid));
bcb02034 658 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
630f3f0c 659 sizeof(struct cifs_sid)); */
bcb02034 660
ef571cad 661 return 0;
bcb02034 662}
b9c7a2bb
SF
663
664
97837582
SF
665/* Convert permission bits from mode to equivalent CIFS ACL */
666static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
cce246ee 667 struct inode *inode, __u64 nmode)
97837582
SF
668{
669 int rc = 0;
670 __u32 dacloffset;
671 __u32 ndacloffset;
672 __u32 sidsoffset;
673 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
674 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
675 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
676
677 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
ef571cad 678 return -EIO;
97837582
SF
679
680 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
681 le32_to_cpu(pntsd->osidoffset));
682 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
683 le32_to_cpu(pntsd->gsidoffset));
684
685 dacloffset = le32_to_cpu(pntsd->dacloffset);
686 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
687
688 ndacloffset = sizeof(struct cifs_ntsd);
689 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
690 ndacl_ptr->revision = dacl_ptr->revision;
691 ndacl_ptr->size = 0;
692 ndacl_ptr->num_aces = 0;
693
694 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
695
696 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
697
698 /* copy security descriptor control portion and owner and group sid */
699 copy_sec_desc(pntsd, pnntsd, sidsoffset);
700
ef571cad 701 return rc;
97837582
SF
702}
703
1bf4072d
CH
704static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
705 __u16 fid, u32 *pacllen)
b9c7a2bb 706{
b9c7a2bb 707 struct cifs_ntsd *pntsd = NULL;
1bf4072d 708 int xid, rc;
7ffec372
JL
709 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
710
711 if (IS_ERR(tlink))
987b21d7 712 return ERR_CAST(tlink);
b9c7a2bb 713
1bf4072d 714 xid = GetXid();
7ffec372 715 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
1bf4072d 716 FreeXid(xid);
b9c7a2bb 717
7ffec372 718 cifs_put_tlink(tlink);
b9c7a2bb 719
987b21d7
SP
720 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
721 if (rc)
722 return ERR_PTR(rc);
1bf4072d
CH
723 return pntsd;
724}
8b1327f6 725
1bf4072d
CH
726static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
727 const char *path, u32 *pacllen)
728{
729 struct cifs_ntsd *pntsd = NULL;
730 int oplock = 0;
731 int xid, rc;
732 __u16 fid;
7ffec372
JL
733 struct cifsTconInfo *tcon;
734 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
735
736 if (IS_ERR(tlink))
987b21d7 737 return ERR_CAST(tlink);
b9c7a2bb 738
7ffec372 739 tcon = tlink_tcon(tlink);
1bf4072d
CH
740 xid = GetXid();
741
7ffec372 742 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
1bf4072d
CH
743 &fid, &oplock, NULL, cifs_sb->local_nls,
744 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
987b21d7
SP
745 if (!rc) {
746 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
747 CIFSSMBClose(xid, tcon, fid);
b9c7a2bb
SF
748 }
749
7ffec372 750 cifs_put_tlink(tlink);
7505e052 751 FreeXid(xid);
987b21d7
SP
752
753 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
754 if (rc)
755 return ERR_PTR(rc);
7505e052
SF
756 return pntsd;
757}
758
1bf4072d 759/* Retrieve an ACL from the server */
fbeba8bb 760struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1bf4072d
CH
761 struct inode *inode, const char *path,
762 u32 *pacllen)
763{
764 struct cifs_ntsd *pntsd = NULL;
765 struct cifsFileInfo *open_file = NULL;
766
767 if (inode)
6508d904 768 open_file = find_readable_file(CIFS_I(inode), true);
1bf4072d
CH
769 if (!open_file)
770 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
771
772 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
6ab409b5 773 cifsFileInfo_put(open_file);
1bf4072d
CH
774 return pntsd;
775}
776
b96d31a6
CH
777static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
778 struct cifs_ntsd *pnntsd, u32 acllen)
97837582 779{
b96d31a6 780 int xid, rc;
7ffec372
JL
781 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
782
783 if (IS_ERR(tlink))
784 return PTR_ERR(tlink);
97837582 785
b96d31a6 786 xid = GetXid();
7ffec372 787 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
b96d31a6 788 FreeXid(xid);
7ffec372 789 cifs_put_tlink(tlink);
97837582 790
b6b38f70 791 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
b96d31a6
CH
792 return rc;
793}
97837582 794
b96d31a6
CH
795static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
796 struct cifs_ntsd *pnntsd, u32 acllen)
797{
798 int oplock = 0;
799 int xid, rc;
800 __u16 fid;
7ffec372
JL
801 struct cifsTconInfo *tcon;
802 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
97837582 803
7ffec372
JL
804 if (IS_ERR(tlink))
805 return PTR_ERR(tlink);
806
807 tcon = tlink_tcon(tlink);
97837582
SF
808 xid = GetXid();
809
7ffec372 810 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
b96d31a6
CH
811 &fid, &oplock, NULL, cifs_sb->local_nls,
812 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
813 if (rc) {
b6b38f70 814 cERROR(1, "Unable to open file to set ACL");
b96d31a6 815 goto out;
97837582
SF
816 }
817
7ffec372 818 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
b6b38f70 819 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
97837582 820
7ffec372
JL
821 CIFSSMBClose(xid, tcon, fid);
822out:
97837582 823 FreeXid(xid);
7ffec372 824 cifs_put_tlink(tlink);
b96d31a6
CH
825 return rc;
826}
97837582 827
b96d31a6 828/* Set an ACL on the server */
b73b9a4b 829int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
b96d31a6
CH
830 struct inode *inode, const char *path)
831{
832 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
833 struct cifsFileInfo *open_file;
834 int rc;
835
b6b38f70 836 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
b96d31a6 837
6508d904 838 open_file = find_readable_file(CIFS_I(inode), true);
b96d31a6
CH
839 if (!open_file)
840 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
841
842 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
6ab409b5 843 cifsFileInfo_put(open_file);
ef571cad 844 return rc;
97837582
SF
845}
846
7505e052 847/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
987b21d7 848int
0b8f18e3
JL
849cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
850 struct inode *inode, const char *path, const __u16 *pfid)
7505e052
SF
851{
852 struct cifs_ntsd *pntsd = NULL;
853 u32 acllen = 0;
854 int rc = 0;
855
b6b38f70 856 cFYI(DBG2, "converting ACL to mode for %s", path);
1bf4072d
CH
857
858 if (pfid)
859 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
860 else
861 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
7505e052
SF
862
863 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
987b21d7
SP
864 if (IS_ERR(pntsd)) {
865 rc = PTR_ERR(pntsd);
866 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
867 } else {
0b8f18e3 868 rc = parse_sec_desc(pntsd, acllen, fattr);
987b21d7
SP
869 kfree(pntsd);
870 if (rc)
871 cERROR(1, "parse sec desc failed rc = %d", rc);
872 }
7505e052 873
987b21d7 874 return rc;
b9c7a2bb 875}
953f8681 876
7505e052 877/* Convert mode bits to an ACL so we can update the ACL on the server */
78415d2d 878int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
953f8681
SF
879{
880 int rc = 0;
cce246ee 881 __u32 secdesclen = 0;
97837582
SF
882 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
883 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
953f8681 884
b6b38f70 885 cFYI(DBG2, "set ACL from mode for %s", path);
953f8681
SF
886
887 /* Get the security descriptor */
1bf4072d 888 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
953f8681 889
97837582
SF
890 /* Add three ACEs for owner, group, everyone getting rid of
891 other ACEs as chmod disables ACEs and set the security descriptor */
953f8681 892
987b21d7
SP
893 if (IS_ERR(pntsd)) {
894 rc = PTR_ERR(pntsd);
895 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
896 } else {
97837582
SF
897 /* allocate memory for the smb header,
898 set security descriptor request security descriptor
899 parameters, and secuirty descriptor itself */
953f8681 900
cce246ee
SF
901 secdesclen = secdesclen < DEFSECDESCLEN ?
902 DEFSECDESCLEN : secdesclen;
903 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
97837582 904 if (!pnntsd) {
b6b38f70 905 cERROR(1, "Unable to allocate security descriptor");
97837582 906 kfree(pntsd);
ef571cad 907 return -ENOMEM;
97837582 908 }
7505e052 909
cce246ee 910 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
97837582 911
b6b38f70 912 cFYI(DBG2, "build_sec_desc rc: %d", rc);
97837582
SF
913
914 if (!rc) {
915 /* Set the security descriptor */
cce246ee 916 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
b6b38f70 917 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
97837582
SF
918 }
919
920 kfree(pnntsd);
921 kfree(pntsd);
922 }
923
ef571cad 924 return rc;
953f8681 925}