]> Git Repo - linux.git/blame - fs/cifs/cifsacl.c
cifs: Use BUILD_BUG_ON to validate uids and gids are the same size
[linux.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 ([email protected])
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
2fbc2f17 36/* security id for everyone/world system group */
e01b6400
SP
37static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
2fbc2f17
SP
39/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
4f61258f 41 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
bcb02034 42/* group users */
ad7a2926 43static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 44
b1a6dc21 45static const struct cred *root_cred;
9409ae58 46
4d79dba0 47static int
cf7f601c 48cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
4d79dba0
SP
49{
50 char *payload;
51
41a9f1f6
JL
52 /*
53 * If the payload is less than or equal to the size of a pointer, then
54 * an allocation here is wasteful. Just copy the data directly to the
55 * payload.value union member instead.
56 *
57 * With this however, you must check the datalen before trying to
58 * dereference payload.data!
59 */
1f630680 60 if (prep->datalen <= sizeof(key->payload)) {
41a9f1f6
JL
61 key->payload.value = 0;
62 memcpy(&key->payload.value, prep->data, prep->datalen);
63 key->datalen = prep->datalen;
64 return 0;
65 }
cf7f601c 66 payload = kmalloc(prep->datalen, GFP_KERNEL);
4d79dba0
SP
67 if (!payload)
68 return -ENOMEM;
69
cf7f601c 70 memcpy(payload, prep->data, prep->datalen);
4d79dba0 71 key->payload.data = payload;
cf7f601c 72 key->datalen = prep->datalen;
4d79dba0
SP
73 return 0;
74}
75
76static inline void
77cifs_idmap_key_destroy(struct key *key)
78{
1f630680 79 if (key->datalen > sizeof(key->payload))
41a9f1f6 80 kfree(key->payload.data);
4d79dba0
SP
81}
82
b1a6dc21 83static struct key_type cifs_idmap_key_type = {
c4aca0c0 84 .name = "cifs.idmap",
4d79dba0
SP
85 .instantiate = cifs_idmap_key_instantiate,
86 .destroy = cifs_idmap_key_destroy,
87 .describe = user_describe,
88 .match = user_match,
89};
90
faa65f07
JL
91static char *
92sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
9409ae58 93{
faa65f07 94 int i, len;
ee13b2ba 95 unsigned int saval;
faa65f07 96 char *sidstr, *strptr;
193cdd8a 97 unsigned long long id_auth_val;
9409ae58 98
faa65f07
JL
99 /* 3 bytes for prefix */
100 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
101 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
102 GFP_KERNEL);
103 if (!sidstr)
104 return sidstr;
9409ae58 105
faa65f07
JL
106 strptr = sidstr;
107 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
108 sidptr->revision);
109 strptr += len;
9409ae58 110
193cdd8a
JL
111 /* The authority field is a single 48-bit number */
112 id_auth_val = (unsigned long long)sidptr->authority[5];
113 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
114 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
115 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
116 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
117 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
118
119 /*
120 * MS-DTYP states that if the authority is >= 2^32, then it should be
121 * expressed as a hex value.
122 */
123 if (id_auth_val <= UINT_MAX)
124 len = sprintf(strptr, "-%llu", id_auth_val);
125 else
126 len = sprintf(strptr, "-0x%llx", id_auth_val);
127
128 strptr += len;
9409ae58
SP
129
130 for (i = 0; i < sidptr->num_subauth; ++i) {
131 saval = le32_to_cpu(sidptr->sub_auth[i]);
faa65f07
JL
132 len = sprintf(strptr, "-%u", saval);
133 strptr += len;
9409ae58 134 }
faa65f07
JL
135
136 return sidstr;
9409ae58
SP
137}
138
436bb435
JL
139/*
140 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
141 * the same returns zero, if they do not match returns non-zero.
142 */
143static int
144compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
145{
146 int i;
147 int num_subauth, num_sat, num_saw;
148
149 if ((!ctsid) || (!cwsid))
150 return 1;
151
152 /* compare the revision */
153 if (ctsid->revision != cwsid->revision) {
154 if (ctsid->revision > cwsid->revision)
155 return 1;
156 else
157 return -1;
158 }
159
160 /* compare all of the six auth values */
161 for (i = 0; i < NUM_AUTHS; ++i) {
162 if (ctsid->authority[i] != cwsid->authority[i]) {
163 if (ctsid->authority[i] > cwsid->authority[i])
164 return 1;
165 else
166 return -1;
167 }
168 }
169
170 /* compare all of the subauth values if any */
171 num_sat = ctsid->num_subauth;
172 num_saw = cwsid->num_subauth;
173 num_subauth = num_sat < num_saw ? num_sat : num_saw;
174 if (num_subauth) {
175 for (i = 0; i < num_subauth; ++i) {
176 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
177 if (le32_to_cpu(ctsid->sub_auth[i]) >
178 le32_to_cpu(cwsid->sub_auth[i]))
179 return 1;
180 else
181 return -1;
182 }
183 }
184 }
185
186 return 0; /* sids compare/match */
187}
188
36960e44
JL
189static void
190cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
191{
36f87ee7
JL
192 int i;
193
194 dst->revision = src->revision;
30c9d6cc 195 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
36f87ee7
JL
196 for (i = 0; i < NUM_AUTHS; ++i)
197 dst->authority[i] = src->authority[i];
198 for (i = 0; i < dst->num_subauth; ++i)
199 dst->sub_auth[i] = src->sub_auth[i];
36960e44
JL
200}
201
9409ae58 202static int
faa65f07 203id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
9409ae58 204{
faa65f07 205 int rc;
21fed0d5 206 struct key *sidkey;
2ae03025
JL
207 struct cifs_sid *ksid;
208 unsigned int ksid_size;
faa65f07 209 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
21fed0d5 210 const struct cred *saved_cred;
21fed0d5 211
faa65f07
JL
212 rc = snprintf(desc, sizeof(desc), "%ci:%u",
213 sidtype == SIDOWNER ? 'o' : 'g', cid);
214 if (rc >= sizeof(desc))
215 return -EINVAL;
21fed0d5 216
faa65f07
JL
217 rc = 0;
218 saved_cred = override_creds(root_cred);
219 sidkey = request_key(&cifs_idmap_key_type, desc, "");
220 if (IS_ERR(sidkey)) {
21fed0d5 221 rc = -EINVAL;
faa65f07
JL
222 cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
223 sidtype == SIDOWNER ? 'u' : 'g', cid);
224 goto out_revert_creds;
225 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
226 rc = -EIO;
227 cFYI(1, "%s: Downcall contained malformed key "
228 "(datalen=%hu)", __func__, sidkey->datalen);
2ae03025 229 goto invalidate_key;
21fed0d5 230 }
2ae03025 231
1f630680
JL
232 /*
233 * A sid is usually too large to be embedded in payload.value, but if
234 * there are no subauthorities and the host has 8-byte pointers, then
235 * it could be.
236 */
237 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
238 (struct cifs_sid *)&sidkey->payload.value :
239 (struct cifs_sid *)sidkey->payload.data;
240
2ae03025
JL
241 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
242 if (ksid_size > sidkey->datalen) {
243 rc = -EIO;
244 cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, "
245 "ksid_size=%u)", __func__, sidkey->datalen, ksid_size);
246 goto invalidate_key;
247 }
1f630680 248
2ae03025 249 cifs_copy_sid(ssid, ksid);
faa65f07
JL
250out_key_put:
251 key_put(sidkey);
252out_revert_creds:
253 revert_creds(saved_cred);
21fed0d5 254 return rc;
2ae03025
JL
255
256invalidate_key:
257 key_invalidate(sidkey);
258 goto out_key_put;
21fed0d5
SP
259}
260
9409ae58
SP
261static int
262sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
263 struct cifs_fattr *fattr, uint sidtype)
264{
265 int rc;
faa65f07
JL
266 struct key *sidkey;
267 char *sidstr;
9409ae58 268 const struct cred *saved_cred;
faa65f07
JL
269 uid_t fuid = cifs_sb->mnt_uid;
270 gid_t fgid = cifs_sb->mnt_gid;
9409ae58
SP
271
272 /*
faa65f07
JL
273 * If we have too many subauthorities, then something is really wrong.
274 * Just return an error.
9409ae58 275 */
faa65f07
JL
276 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
277 cFYI(1, "%s: %u subauthorities is too many!", __func__,
278 psid->num_subauth);
279 return -EIO;
9409ae58
SP
280 }
281
faa65f07
JL
282 sidstr = sid_to_key_str(psid, sidtype);
283 if (!sidstr)
284 return -ENOMEM;
285
286 saved_cred = override_creds(root_cred);
287 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
288 if (IS_ERR(sidkey)) {
289 rc = -EINVAL;
290 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
291 sidtype == SIDOWNER ? 'u' : 'g');
292 goto out_revert_creds;
293 }
294
295 /*
296 * FIXME: Here we assume that uid_t and gid_t are same size. It's
297 * probably a safe assumption but might be better to check based on
298 * sidtype.
299 */
355958f2 300 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
41a9f1f6 301 if (sidkey->datalen != sizeof(uid_t)) {
faa65f07
JL
302 rc = -EIO;
303 cFYI(1, "%s: Downcall contained malformed key "
304 "(datalen=%hu)", __func__, sidkey->datalen);
2ae03025 305 key_invalidate(sidkey);
faa65f07 306 goto out_key_put;
9409ae58
SP
307 }
308
9409ae58 309 if (sidtype == SIDOWNER)
41a9f1f6 310 memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
9409ae58 311 else
41a9f1f6 312 memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
faa65f07
JL
313
314out_key_put:
315 key_put(sidkey);
316out_revert_creds:
317 revert_creds(saved_cred);
318 kfree(sidstr);
9409ae58 319
faa65f07
JL
320 /*
321 * Note that we return 0 here unconditionally. If the mapping
322 * fails then we just fall back to using the mnt_uid/mnt_gid.
323 */
324 if (sidtype == SIDOWNER)
325 fattr->cf_uid = fuid;
326 else
327 fattr->cf_gid = fgid;
9409ae58
SP
328 return 0;
329}
330
4d79dba0
SP
331int
332init_cifs_idmap(void)
333{
334 struct cred *cred;
335 struct key *keyring;
336 int ret;
337
ac3aa2f8 338 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
4d79dba0
SP
339
340 /* create an override credential set with a special thread keyring in
341 * which requests are cached
342 *
343 * this is used to prevent malicious redirections from being installed
344 * with add_key().
345 */
346 cred = prepare_kernel_cred(NULL);
347 if (!cred)
348 return -ENOMEM;
349
f8aa23a5
DH
350 keyring = keyring_alloc(".cifs_idmap", 0, 0, cred,
351 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
352 KEY_USR_VIEW | KEY_USR_READ,
353 KEY_ALLOC_NOT_IN_QUOTA, NULL);
4d79dba0
SP
354 if (IS_ERR(keyring)) {
355 ret = PTR_ERR(keyring);
356 goto failed_put_cred;
357 }
358
4d79dba0
SP
359 ret = register_key_type(&cifs_idmap_key_type);
360 if (ret < 0)
361 goto failed_put_key;
362
363 /* instruct request_key() to use this special keyring as a cache for
364 * the results it looks up */
700920eb 365 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
4d79dba0
SP
366 cred->thread_keyring = keyring;
367 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
368 root_cred = cred;
369
ac3aa2f8 370 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
4d79dba0
SP
371 return 0;
372
373failed_put_key:
374 key_put(keyring);
375failed_put_cred:
376 put_cred(cred);
377 return ret;
378}
379
380void
381exit_cifs_idmap(void)
382{
383 key_revoke(root_cred->thread_keyring);
384 unregister_key_type(&cifs_idmap_key_type);
385 put_cred(root_cred);
ac3aa2f8 386 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
4d79dba0
SP
387}
388
97837582
SF
389/* copy ntsd, owner sid, and group sid from a security descriptor to another */
390static void copy_sec_desc(const struct cifs_ntsd *pntsd,
391 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
392{
97837582
SF
393 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
394 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
395
396 /* copy security descriptor control portion */
397 pnntsd->revision = pntsd->revision;
398 pnntsd->type = pntsd->type;
399 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
400 pnntsd->sacloffset = 0;
401 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
402 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
403
404 /* copy owner sid */
405 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
406 le32_to_cpu(pntsd->osidoffset));
407 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
36960e44 408 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
97837582
SF
409
410 /* copy group sid */
411 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
412 le32_to_cpu(pntsd->gsidoffset));
413 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
414 sizeof(struct cifs_sid));
36960e44 415 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
97837582
SF
416
417 return;
418}
419
420
630f3f0c
SF
421/*
422 change posix mode to reflect permissions
423 pmode is the existing mode (we only want to overwrite part of this
424 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
425*/
9b5e6857 426static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
15b03959 427 umode_t *pbits_to_set)
630f3f0c 428{
9b5e6857 429 __u32 flags = le32_to_cpu(ace_flags);
15b03959 430 /* the order of ACEs is important. The canonical order is to begin with
ce06c9f0 431 DENY entries followed by ALLOW, otherwise an allow entry could be
15b03959 432 encountered first, making the subsequent deny entry like "dead code"
ce06c9f0 433 which would be superflous since Windows stops when a match is made
15b03959
SF
434 for the operation you are trying to perform for your user */
435
436 /* For deny ACEs we change the mask so that subsequent allow access
437 control entries do not turn on the bits we are denying */
438 if (type == ACCESS_DENIED) {
ad7a2926 439 if (flags & GENERIC_ALL)
15b03959 440 *pbits_to_set &= ~S_IRWXUGO;
ad7a2926 441
9b5e6857
AV
442 if ((flags & GENERIC_WRITE) ||
443 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 444 *pbits_to_set &= ~S_IWUGO;
9b5e6857
AV
445 if ((flags & GENERIC_READ) ||
446 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 447 *pbits_to_set &= ~S_IRUGO;
9b5e6857
AV
448 if ((flags & GENERIC_EXECUTE) ||
449 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959
SF
450 *pbits_to_set &= ~S_IXUGO;
451 return;
452 } else if (type != ACCESS_ALLOWED) {
b6b38f70 453 cERROR(1, "unknown access control type %d", type);
15b03959
SF
454 return;
455 }
456 /* else ACCESS_ALLOWED type */
630f3f0c 457
9b5e6857 458 if (flags & GENERIC_ALL) {
15b03959 459 *pmode |= (S_IRWXUGO & (*pbits_to_set));
b6b38f70 460 cFYI(DBG2, "all perms");
d61e5808
SF
461 return;
462 }
9b5e6857
AV
463 if ((flags & GENERIC_WRITE) ||
464 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 465 *pmode |= (S_IWUGO & (*pbits_to_set));
9b5e6857
AV
466 if ((flags & GENERIC_READ) ||
467 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 468 *pmode |= (S_IRUGO & (*pbits_to_set));
9b5e6857
AV
469 if ((flags & GENERIC_EXECUTE) ||
470 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 471 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 472
b6b38f70 473 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
630f3f0c
SF
474 return;
475}
476
ce06c9f0
SF
477/*
478 Generate access flags to reflect permissions mode is the existing mode.
479 This function is called for every ACE in the DACL whose SID matches
480 with either owner or group or everyone.
481*/
482
483static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
484 __u32 *pace_flags)
485{
486 /* reset access mask */
487 *pace_flags = 0x0;
488
489 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
490 mode &= bits_to_use;
491
492 /* check for R/W/X UGO since we do not know whose flags
493 is this but we have cleared all the bits sans RWX for
494 either user or group or other as per bits_to_use */
495 if (mode & S_IRUGO)
496 *pace_flags |= SET_FILE_READ_RIGHTS;
497 if (mode & S_IWUGO)
498 *pace_flags |= SET_FILE_WRITE_RIGHTS;
499 if (mode & S_IXUGO)
500 *pace_flags |= SET_FILE_EXEC_RIGHTS;
501
b6b38f70 502 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
ce06c9f0
SF
503 return;
504}
505
2b210adc 506static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
97837582
SF
507 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
508{
509 int i;
510 __u16 size = 0;
511 __u32 access_req = 0;
512
513 pntace->type = ACCESS_ALLOWED;
514 pntace->flags = 0x0;
515 mode_to_access_flags(nmode, bits, &access_req);
516 if (!access_req)
517 access_req = SET_MINIMUM_RIGHTS;
518 pntace->access_req = cpu_to_le32(access_req);
519
520 pntace->sid.revision = psid->revision;
521 pntace->sid.num_subauth = psid->num_subauth;
852e2295 522 for (i = 0; i < NUM_AUTHS; i++)
97837582
SF
523 pntace->sid.authority[i] = psid->authority[i];
524 for (i = 0; i < psid->num_subauth; i++)
525 pntace->sid.sub_auth[i] = psid->sub_auth[i];
526
527 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
528 pntace->size = cpu_to_le16(size);
529
ef571cad 530 return size;
97837582
SF
531}
532
297647c2 533
953f8681
SF
534#ifdef CONFIG_CIFS_DEBUG2
535static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 536{
d0d66c44 537 int num_subauth;
d0d66c44
SP
538
539 /* validate that we do not go past end of acl */
297647c2 540
44093ca2 541 if (le16_to_cpu(pace->size) < 16) {
b6b38f70 542 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
44093ca2
SF
543 return;
544 }
545
546 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
b6b38f70 547 cERROR(1, "ACL too small to parse ACE");
d0d66c44 548 return;
44093ca2 549 }
d0d66c44 550
44093ca2 551 num_subauth = pace->sid.num_subauth;
d0d66c44 552 if (num_subauth) {
8f18c131 553 int i;
b6b38f70 554 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
44093ca2 555 pace->sid.revision, pace->sid.num_subauth, pace->type,
b6b38f70 556 pace->flags, le16_to_cpu(pace->size));
d12fd121 557 for (i = 0; i < num_subauth; ++i) {
b6b38f70
JP
558 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
559 le32_to_cpu(pace->sid.sub_auth[i]));
d12fd121
SF
560 }
561
562 /* BB add length check to make sure that we do not have huge
563 num auths and therefore go off the end */
d12fd121
SF
564 }
565
566 return;
567}
953f8681 568#endif
d12fd121 569
d0d66c44 570
a750e77c 571static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 572 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
0b8f18e3 573 struct cifs_fattr *fattr)
d0d66c44
SP
574{
575 int i;
576 int num_aces = 0;
577 int acl_size;
578 char *acl_base;
d0d66c44
SP
579 struct cifs_ace **ppace;
580
581 /* BB need to add parm so we can store the SID BB */
582
2b83457b
SF
583 if (!pdacl) {
584 /* no DACL in the security descriptor, set
585 all the permissions for user/group/other */
0b8f18e3 586 fattr->cf_mode |= S_IRWXUGO;
2b83457b
SF
587 return;
588 }
589
d0d66c44 590 /* validate that we do not go past end of acl */
af6f4612 591 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
b6b38f70 592 cERROR(1, "ACL too small to parse DACL");
d0d66c44
SP
593 return;
594 }
595
b6b38f70 596 cFYI(DBG2, "DACL revision %d size %d num aces %d",
af6f4612 597 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
b6b38f70 598 le32_to_cpu(pdacl->num_aces));
d0d66c44 599
7505e052
SF
600 /* reset rwx permissions for user/group/other.
601 Also, if num_aces is 0 i.e. DACL has no ACEs,
602 user/group/other have no permissions */
0b8f18e3 603 fattr->cf_mode &= ~(S_IRWXUGO);
7505e052 604
d0d66c44
SP
605 acl_base = (char *)pdacl;
606 acl_size = sizeof(struct cifs_acl);
607
adbc0358 608 num_aces = le32_to_cpu(pdacl->num_aces);
a5ff3769 609 if (num_aces > 0) {
15b03959
SF
610 umode_t user_mask = S_IRWXU;
611 umode_t group_mask = S_IRWXG;
2fbc2f17 612 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
15b03959 613
7250170c
DC
614 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
615 return;
d0d66c44
SP
616 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
617 GFP_KERNEL);
8132b65b
SF
618 if (!ppace) {
619 cERROR(1, "DACL memory allocation error");
620 return;
621 }
d0d66c44 622
d0d66c44 623 for (i = 0; i < num_aces; ++i) {
44093ca2 624 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
625#ifdef CONFIG_CIFS_DEBUG2
626 dump_ace(ppace[i], end_of_acl);
627#endif
9409ae58 628 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
e01b6400 629 access_flags_to_mode(ppace[i]->access_req,
15b03959 630 ppace[i]->type,
0b8f18e3 631 &fattr->cf_mode,
15b03959 632 &user_mask);
9409ae58 633 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
e01b6400 634 access_flags_to_mode(ppace[i]->access_req,
15b03959 635 ppace[i]->type,
0b8f18e3 636 &fattr->cf_mode,
15b03959 637 &group_mask);
9409ae58 638 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
e01b6400 639 access_flags_to_mode(ppace[i]->access_req,
15b03959 640 ppace[i]->type,
0b8f18e3 641 &fattr->cf_mode,
15b03959 642 &other_mask);
9409ae58 643 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
2fbc2f17
SP
644 access_flags_to_mode(ppace[i]->access_req,
645 ppace[i]->type,
646 &fattr->cf_mode,
647 &other_mask);
648
e01b6400 649
44093ca2 650/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
651 (void *)ppace[i],
652 sizeof(struct cifs_ace)); */
d0d66c44 653
44093ca2
SF
654 acl_base = (char *)ppace[i];
655 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
656 }
657
658 kfree(ppace);
d0d66c44
SP
659 }
660
661 return;
662}
663
bcb02034 664
97837582
SF
665static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
666 struct cifs_sid *pgrpsid, __u64 nmode)
667{
2b210adc 668 u16 size = 0;
97837582
SF
669 struct cifs_acl *pnndacl;
670
671 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
672
673 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
674 pownersid, nmode, S_IRWXU);
675 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
676 pgrpsid, nmode, S_IRWXG);
677 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
678 &sid_everyone, nmode, S_IRWXO);
679
680 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
d9f382ef 681 pndacl->num_aces = cpu_to_le32(3);
97837582 682
ef571cad 683 return 0;
97837582
SF
684}
685
686
bcb02034
SF
687static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
688{
689 /* BB need to add parm so we can store the SID BB */
690
b9c7a2bb
SF
691 /* validate that we do not go past end of ACL - sid must be at least 8
692 bytes long (assuming no sub-auths - e.g. the null SID */
693 if (end_of_acl < (char *)psid + 8) {
b6b38f70 694 cERROR(1, "ACL too small to parse SID %p", psid);
bcb02034
SF
695 return -EINVAL;
696 }
d0d66c44 697
bcb02034 698#ifdef CONFIG_CIFS_DEBUG2
fc03d8a5 699 if (psid->num_subauth) {
8f18c131 700 int i;
b6b38f70
JP
701 cFYI(1, "SID revision %d num_auth %d",
702 psid->revision, psid->num_subauth);
bcb02034 703
af6f4612 704 for (i = 0; i < psid->num_subauth; i++) {
b6b38f70
JP
705 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
706 le32_to_cpu(psid->sub_auth[i]));
d0d66c44
SP
707 }
708
d12fd121 709 /* BB add length check to make sure that we do not have huge
d0d66c44 710 num auths and therefore go off the end */
b6b38f70
JP
711 cFYI(1, "RID 0x%x",
712 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
d0d66c44 713 }
fc03d8a5 714#endif
d0d66c44 715
bcb02034
SF
716 return 0;
717}
718
d0d66c44 719
bcb02034 720/* Convert CIFS ACL to POSIX form */
9409ae58
SP
721static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
722 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
bcb02034 723{
9409ae58 724 int rc = 0;
bcb02034
SF
725 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
726 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 727 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 728 __u32 dacloffset;
bcb02034 729
0b8f18e3 730 if (pntsd == NULL)
b9c7a2bb
SF
731 return -EIO;
732
bcb02034 733 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 734 le32_to_cpu(pntsd->osidoffset));
bcb02034 735 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 736 le32_to_cpu(pntsd->gsidoffset));
7505e052 737 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 738 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
b6b38f70 739 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
bcb02034 740 "sacloffset 0x%x dacloffset 0x%x",
af6f4612
SF
741 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
742 le32_to_cpu(pntsd->gsidoffset),
b6b38f70 743 le32_to_cpu(pntsd->sacloffset), dacloffset);
b9c7a2bb 744/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034 745 rc = parse_sid(owner_sid_ptr, end_of_acl);
9409ae58
SP
746 if (rc) {
747 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
748 return rc;
749 }
750 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
751 if (rc) {
752 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
bcb02034 753 return rc;
9409ae58 754 }
bcb02034
SF
755
756 rc = parse_sid(group_sid_ptr, end_of_acl);
9409ae58
SP
757 if (rc) {
758 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
bcb02034 759 return rc;
9409ae58
SP
760 }
761 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
762 if (rc) {
763 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
764 return rc;
765 }
bcb02034 766
7505e052
SF
767 if (dacloffset)
768 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
0b8f18e3 769 group_sid_ptr, fattr);
7505e052 770 else
b6b38f70 771 cFYI(1, "no ACL"); /* BB grant all or default perms? */
d0d66c44 772
9409ae58 773 return rc;
bcb02034 774}
b9c7a2bb 775
97837582
SF
776/* Convert permission bits from mode to equivalent CIFS ACL */
777static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
a5ff3769 778 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
97837582
SF
779{
780 int rc = 0;
781 __u32 dacloffset;
782 __u32 ndacloffset;
783 __u32 sidsoffset;
784 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
a5ff3769 785 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
97837582
SF
786 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
787 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
788
a5ff3769
SP
789 if (nmode != NO_CHANGE_64) { /* chmod */
790 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
97837582 791 le32_to_cpu(pntsd->osidoffset));
a5ff3769 792 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
97837582 793 le32_to_cpu(pntsd->gsidoffset));
a5ff3769
SP
794 dacloffset = le32_to_cpu(pntsd->dacloffset);
795 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
796 ndacloffset = sizeof(struct cifs_ntsd);
797 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
798 ndacl_ptr->revision = dacl_ptr->revision;
799 ndacl_ptr->size = 0;
800 ndacl_ptr->num_aces = 0;
801
802 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
803 nmode);
804 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
805 /* copy sec desc control portion & owner and group sids */
806 copy_sec_desc(pntsd, pnntsd, sidsoffset);
807 *aclflag = CIFS_ACL_DACL;
808 } else {
809 memcpy(pnntsd, pntsd, secdesclen);
810 if (uid != NO_CHANGE_32) { /* chown */
811 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
812 le32_to_cpu(pnntsd->osidoffset));
813 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
814 GFP_KERNEL);
815 if (!nowner_sid_ptr)
816 return -ENOMEM;
817 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
818 if (rc) {
819 cFYI(1, "%s: Mapping error %d for owner id %d",
820 __func__, rc, uid);
821 kfree(nowner_sid_ptr);
822 return rc;
823 }
36960e44 824 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
a5ff3769
SP
825 kfree(nowner_sid_ptr);
826 *aclflag = CIFS_ACL_OWNER;
827 }
828 if (gid != NO_CHANGE_32) { /* chgrp */
829 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
830 le32_to_cpu(pnntsd->gsidoffset));
831 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
832 GFP_KERNEL);
833 if (!ngroup_sid_ptr)
834 return -ENOMEM;
835 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
836 if (rc) {
837 cFYI(1, "%s: Mapping error %d for group id %d",
838 __func__, rc, gid);
839 kfree(ngroup_sid_ptr);
840 return rc;
841 }
36960e44 842 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
a5ff3769
SP
843 kfree(ngroup_sid_ptr);
844 *aclflag = CIFS_ACL_GROUP;
845 }
846 }
97837582 847
ef571cad 848 return rc;
97837582
SF
849}
850
1bf4072d
CH
851static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
852 __u16 fid, u32 *pacllen)
b9c7a2bb 853{
b9c7a2bb 854 struct cifs_ntsd *pntsd = NULL;
6d5786a3
PS
855 unsigned int xid;
856 int rc;
7ffec372
JL
857 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
858
859 if (IS_ERR(tlink))
987b21d7 860 return ERR_CAST(tlink);
b9c7a2bb 861
6d5786a3 862 xid = get_xid();
7ffec372 863 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
6d5786a3 864 free_xid(xid);
b9c7a2bb 865
7ffec372 866 cifs_put_tlink(tlink);
b9c7a2bb 867
987b21d7
SP
868 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
869 if (rc)
870 return ERR_PTR(rc);
1bf4072d
CH
871 return pntsd;
872}
8b1327f6 873
1bf4072d
CH
874static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
875 const char *path, u32 *pacllen)
876{
877 struct cifs_ntsd *pntsd = NULL;
878 int oplock = 0;
6d5786a3
PS
879 unsigned int xid;
880 int rc, create_options = 0;
1bf4072d 881 __u16 fid;
96daf2b0 882 struct cifs_tcon *tcon;
7ffec372
JL
883 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
884
885 if (IS_ERR(tlink))
987b21d7 886 return ERR_CAST(tlink);
b9c7a2bb 887
7ffec372 888 tcon = tlink_tcon(tlink);
6d5786a3 889 xid = get_xid();
1bf4072d 890
3d3ea8e6
SP
891 if (backup_cred(cifs_sb))
892 create_options |= CREATE_OPEN_BACKUP_INTENT;
893
894 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
895 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
896 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
987b21d7
SP
897 if (!rc) {
898 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
899 CIFSSMBClose(xid, tcon, fid);
b9c7a2bb
SF
900 }
901
7ffec372 902 cifs_put_tlink(tlink);
6d5786a3 903 free_xid(xid);
987b21d7
SP
904
905 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
906 if (rc)
907 return ERR_PTR(rc);
7505e052
SF
908 return pntsd;
909}
910
1bf4072d 911/* Retrieve an ACL from the server */
fbeba8bb 912struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1bf4072d
CH
913 struct inode *inode, const char *path,
914 u32 *pacllen)
915{
916 struct cifs_ntsd *pntsd = NULL;
917 struct cifsFileInfo *open_file = NULL;
918
919 if (inode)
6508d904 920 open_file = find_readable_file(CIFS_I(inode), true);
1bf4072d
CH
921 if (!open_file)
922 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
923
4b4de76e 924 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
6ab409b5 925 cifsFileInfo_put(open_file);
1bf4072d
CH
926 return pntsd;
927}
928
a5ff3769
SP
929 /* Set an ACL on the server */
930int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
931 struct inode *inode, const char *path, int aclflag)
b96d31a6
CH
932{
933 int oplock = 0;
6d5786a3
PS
934 unsigned int xid;
935 int rc, access_flags, create_options = 0;
b96d31a6 936 __u16 fid;
96daf2b0 937 struct cifs_tcon *tcon;
a5ff3769 938 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
7ffec372 939 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
97837582 940
7ffec372
JL
941 if (IS_ERR(tlink))
942 return PTR_ERR(tlink);
943
944 tcon = tlink_tcon(tlink);
6d5786a3 945 xid = get_xid();
97837582 946
3d3ea8e6
SP
947 if (backup_cred(cifs_sb))
948 create_options |= CREATE_OPEN_BACKUP_INTENT;
949
a5ff3769
SP
950 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
951 access_flags = WRITE_OWNER;
952 else
953 access_flags = WRITE_DAC;
954
955 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
956 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
957 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
b96d31a6 958 if (rc) {
b6b38f70 959 cERROR(1, "Unable to open file to set ACL");
b96d31a6 960 goto out;
97837582
SF
961 }
962
a5ff3769 963 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
b6b38f70 964 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
97837582 965
7ffec372
JL
966 CIFSSMBClose(xid, tcon, fid);
967out:
6d5786a3 968 free_xid(xid);
7ffec372 969 cifs_put_tlink(tlink);
b96d31a6
CH
970 return rc;
971}
97837582 972
7505e052 973/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
987b21d7 974int
0b8f18e3
JL
975cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
976 struct inode *inode, const char *path, const __u16 *pfid)
7505e052
SF
977{
978 struct cifs_ntsd *pntsd = NULL;
979 u32 acllen = 0;
980 int rc = 0;
981
b6b38f70 982 cFYI(DBG2, "converting ACL to mode for %s", path);
1bf4072d
CH
983
984 if (pfid)
985 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
986 else
987 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
7505e052
SF
988
989 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
987b21d7
SP
990 if (IS_ERR(pntsd)) {
991 rc = PTR_ERR(pntsd);
992 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
993 } else {
9409ae58 994 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
987b21d7
SP
995 kfree(pntsd);
996 if (rc)
997 cERROR(1, "parse sec desc failed rc = %d", rc);
998 }
7505e052 999
987b21d7 1000 return rc;
b9c7a2bb 1001}
953f8681 1002
7505e052 1003/* Convert mode bits to an ACL so we can update the ACL on the server */
a5ff3769
SP
1004int
1005id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1006 uid_t uid, gid_t gid)
953f8681
SF
1007{
1008 int rc = 0;
a5ff3769 1009 int aclflag = CIFS_ACL_DACL; /* default flag to set */
cce246ee 1010 __u32 secdesclen = 0;
97837582
SF
1011 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1012 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
953f8681 1013
b6b38f70 1014 cFYI(DBG2, "set ACL from mode for %s", path);
953f8681
SF
1015
1016 /* Get the security descriptor */
1bf4072d 1017 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
987b21d7
SP
1018 if (IS_ERR(pntsd)) {
1019 rc = PTR_ERR(pntsd);
1020 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
c78cd838
JL
1021 goto out;
1022 }
7505e052 1023
c78cd838
JL
1024 /*
1025 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1026 * as chmod disables ACEs and set the security descriptor. Allocate
1027 * memory for the smb header, set security descriptor request security
1028 * descriptor parameters, and secuirty descriptor itself
1029 */
7ee0b4c6 1030 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
c78cd838
JL
1031 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1032 if (!pnntsd) {
1033 cERROR(1, "Unable to allocate security descriptor");
1034 kfree(pntsd);
1035 return -ENOMEM;
1036 }
97837582 1037
c78cd838
JL
1038 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1039 &aclflag);
97837582 1040
c78cd838 1041 cFYI(DBG2, "build_sec_desc rc: %d", rc);
97837582 1042
c78cd838
JL
1043 if (!rc) {
1044 /* Set the security descriptor */
1045 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1046 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
97837582
SF
1047 }
1048
c78cd838
JL
1049 kfree(pnntsd);
1050 kfree(pntsd);
1051out:
ef571cad 1052 return rc;
953f8681 1053}
This page took 0.508708 seconds and 4 git commands to generate.