]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/cifs/cifsacl.c
cifs: fix use of CONFIG_CIFS_ACL
[mirror_ubuntu-artful-kernel.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>
65874007
SF
26#include "cifspdu.h"
27#include "cifsglob.h"
d0d66c44 28#include "cifsacl.h"
65874007
SF
29#include "cifsproto.h"
30#include "cifs_debug.h"
65874007 31
297647c2 32
af6f4612 33static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
297647c2
SF
34 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
35 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
536abdb0
JL
36 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
37 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
38 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
39 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
40 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
44093ca2 41;
297647c2
SF
42
43
bcb02034 44/* security id for everyone */
e01b6400
SP
45static const struct cifs_sid sid_everyone = {
46 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
bcb02034 47/* group users */
ad7a2926 48static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 49
297647c2
SF
50
51int match_sid(struct cifs_sid *ctsid)
52{
53 int i, j;
54 int num_subauth, num_sat, num_saw;
55 struct cifs_sid *cwsid;
56
57 if (!ctsid)
ef571cad 58 return -1;
297647c2
SF
59
60 for (i = 0; i < NUM_WK_SIDS; ++i) {
61 cwsid = &(wksidarr[i].cifssid);
62
63 /* compare the revision */
64 if (ctsid->revision != cwsid->revision)
65 continue;
66
67 /* compare all of the six auth values */
68 for (j = 0; j < 6; ++j) {
69 if (ctsid->authority[j] != cwsid->authority[j])
70 break;
71 }
72 if (j < 6)
73 continue; /* all of the auth values did not match */
74
75 /* compare all of the subauth values if any */
ce51ae14
DK
76 num_sat = ctsid->num_subauth;
77 num_saw = cwsid->num_subauth;
297647c2
SF
78 num_subauth = num_sat < num_saw ? num_sat : num_saw;
79 if (num_subauth) {
80 for (j = 0; j < num_subauth; ++j) {
81 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
82 break;
83 }
84 if (j < num_subauth)
85 continue; /* all sub_auth values do not match */
86 }
87
b6b38f70 88 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
ef571cad 89 return 0; /* sids compare/match */
297647c2
SF
90 }
91
b6b38f70 92 cFYI(1, "No matching sid");
ef571cad 93 return -1;
297647c2
SF
94}
95
a750e77c
SF
96/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
97 the same returns 1, if they do not match returns 0 */
630f3f0c 98int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
297647c2
SF
99{
100 int i;
101 int num_subauth, num_sat, num_saw;
102
103 if ((!ctsid) || (!cwsid))
ef571cad 104 return 0;
297647c2
SF
105
106 /* compare the revision */
107 if (ctsid->revision != cwsid->revision)
ef571cad 108 return 0;
297647c2
SF
109
110 /* compare all of the six auth values */
111 for (i = 0; i < 6; ++i) {
112 if (ctsid->authority[i] != cwsid->authority[i])
ef571cad 113 return 0;
297647c2
SF
114 }
115
116 /* compare all of the subauth values if any */
adbc0358 117 num_sat = ctsid->num_subauth;
adddd49d 118 num_saw = cwsid->num_subauth;
297647c2
SF
119 num_subauth = num_sat < num_saw ? num_sat : num_saw;
120 if (num_subauth) {
121 for (i = 0; i < num_subauth; ++i) {
122 if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
ef571cad 123 return 0;
297647c2
SF
124 }
125 }
126
ef571cad 127 return 1; /* sids compare/match */
297647c2
SF
128}
129
97837582
SF
130
131/* copy ntsd, owner sid, and group sid from a security descriptor to another */
132static void copy_sec_desc(const struct cifs_ntsd *pntsd,
133 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
134{
135 int i;
136
137 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
138 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
139
140 /* copy security descriptor control portion */
141 pnntsd->revision = pntsd->revision;
142 pnntsd->type = pntsd->type;
143 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
144 pnntsd->sacloffset = 0;
145 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
146 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
147
148 /* copy owner sid */
149 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
150 le32_to_cpu(pntsd->osidoffset));
151 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
152
153 nowner_sid_ptr->revision = owner_sid_ptr->revision;
154 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
155 for (i = 0; i < 6; i++)
156 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
157 for (i = 0; i < 5; i++)
158 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
159
160 /* copy group sid */
161 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
162 le32_to_cpu(pntsd->gsidoffset));
163 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
164 sizeof(struct cifs_sid));
165
166 ngroup_sid_ptr->revision = group_sid_ptr->revision;
167 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
168 for (i = 0; i < 6; i++)
169 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
170 for (i = 0; i < 5; i++)
b1910ad6 171 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
97837582
SF
172
173 return;
174}
175
176
630f3f0c
SF
177/*
178 change posix mode to reflect permissions
179 pmode is the existing mode (we only want to overwrite part of this
180 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
181*/
9b5e6857 182static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
15b03959 183 umode_t *pbits_to_set)
630f3f0c 184{
9b5e6857 185 __u32 flags = le32_to_cpu(ace_flags);
15b03959 186 /* the order of ACEs is important. The canonical order is to begin with
ce06c9f0 187 DENY entries followed by ALLOW, otherwise an allow entry could be
15b03959 188 encountered first, making the subsequent deny entry like "dead code"
ce06c9f0 189 which would be superflous since Windows stops when a match is made
15b03959
SF
190 for the operation you are trying to perform for your user */
191
192 /* For deny ACEs we change the mask so that subsequent allow access
193 control entries do not turn on the bits we are denying */
194 if (type == ACCESS_DENIED) {
ad7a2926 195 if (flags & GENERIC_ALL)
15b03959 196 *pbits_to_set &= ~S_IRWXUGO;
ad7a2926 197
9b5e6857
AV
198 if ((flags & GENERIC_WRITE) ||
199 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 200 *pbits_to_set &= ~S_IWUGO;
9b5e6857
AV
201 if ((flags & GENERIC_READ) ||
202 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 203 *pbits_to_set &= ~S_IRUGO;
9b5e6857
AV
204 if ((flags & GENERIC_EXECUTE) ||
205 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959
SF
206 *pbits_to_set &= ~S_IXUGO;
207 return;
208 } else if (type != ACCESS_ALLOWED) {
b6b38f70 209 cERROR(1, "unknown access control type %d", type);
15b03959
SF
210 return;
211 }
212 /* else ACCESS_ALLOWED type */
630f3f0c 213
9b5e6857 214 if (flags & GENERIC_ALL) {
15b03959 215 *pmode |= (S_IRWXUGO & (*pbits_to_set));
b6b38f70 216 cFYI(DBG2, "all perms");
d61e5808
SF
217 return;
218 }
9b5e6857
AV
219 if ((flags & GENERIC_WRITE) ||
220 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 221 *pmode |= (S_IWUGO & (*pbits_to_set));
9b5e6857
AV
222 if ((flags & GENERIC_READ) ||
223 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 224 *pmode |= (S_IRUGO & (*pbits_to_set));
9b5e6857
AV
225 if ((flags & GENERIC_EXECUTE) ||
226 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 227 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 228
b6b38f70 229 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
630f3f0c
SF
230 return;
231}
232
ce06c9f0
SF
233/*
234 Generate access flags to reflect permissions mode is the existing mode.
235 This function is called for every ACE in the DACL whose SID matches
236 with either owner or group or everyone.
237*/
238
239static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
240 __u32 *pace_flags)
241{
242 /* reset access mask */
243 *pace_flags = 0x0;
244
245 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
246 mode &= bits_to_use;
247
248 /* check for R/W/X UGO since we do not know whose flags
249 is this but we have cleared all the bits sans RWX for
250 either user or group or other as per bits_to_use */
251 if (mode & S_IRUGO)
252 *pace_flags |= SET_FILE_READ_RIGHTS;
253 if (mode & S_IWUGO)
254 *pace_flags |= SET_FILE_WRITE_RIGHTS;
255 if (mode & S_IXUGO)
256 *pace_flags |= SET_FILE_EXEC_RIGHTS;
257
b6b38f70 258 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
ce06c9f0
SF
259 return;
260}
261
2b210adc 262static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
97837582
SF
263 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
264{
265 int i;
266 __u16 size = 0;
267 __u32 access_req = 0;
268
269 pntace->type = ACCESS_ALLOWED;
270 pntace->flags = 0x0;
271 mode_to_access_flags(nmode, bits, &access_req);
272 if (!access_req)
273 access_req = SET_MINIMUM_RIGHTS;
274 pntace->access_req = cpu_to_le32(access_req);
275
276 pntace->sid.revision = psid->revision;
277 pntace->sid.num_subauth = psid->num_subauth;
278 for (i = 0; i < 6; i++)
279 pntace->sid.authority[i] = psid->authority[i];
280 for (i = 0; i < psid->num_subauth; i++)
281 pntace->sid.sub_auth[i] = psid->sub_auth[i];
282
283 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
284 pntace->size = cpu_to_le16(size);
285
ef571cad 286 return size;
97837582
SF
287}
288
297647c2 289
953f8681
SF
290#ifdef CONFIG_CIFS_DEBUG2
291static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 292{
d0d66c44 293 int num_subauth;
d0d66c44
SP
294
295 /* validate that we do not go past end of acl */
297647c2 296
44093ca2 297 if (le16_to_cpu(pace->size) < 16) {
b6b38f70 298 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
44093ca2
SF
299 return;
300 }
301
302 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
b6b38f70 303 cERROR(1, "ACL too small to parse ACE");
d0d66c44 304 return;
44093ca2 305 }
d0d66c44 306
44093ca2 307 num_subauth = pace->sid.num_subauth;
d0d66c44 308 if (num_subauth) {
8f18c131 309 int i;
b6b38f70 310 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
44093ca2 311 pace->sid.revision, pace->sid.num_subauth, pace->type,
b6b38f70 312 pace->flags, le16_to_cpu(pace->size));
d12fd121 313 for (i = 0; i < num_subauth; ++i) {
b6b38f70
JP
314 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
315 le32_to_cpu(pace->sid.sub_auth[i]));
d12fd121
SF
316 }
317
318 /* BB add length check to make sure that we do not have huge
319 num auths and therefore go off the end */
d12fd121
SF
320 }
321
322 return;
323}
953f8681 324#endif
d12fd121 325
d0d66c44 326
a750e77c 327static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 328 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
0b8f18e3 329 struct cifs_fattr *fattr)
d0d66c44
SP
330{
331 int i;
332 int num_aces = 0;
333 int acl_size;
334 char *acl_base;
d0d66c44
SP
335 struct cifs_ace **ppace;
336
337 /* BB need to add parm so we can store the SID BB */
338
2b83457b
SF
339 if (!pdacl) {
340 /* no DACL in the security descriptor, set
341 all the permissions for user/group/other */
0b8f18e3 342 fattr->cf_mode |= S_IRWXUGO;
2b83457b
SF
343 return;
344 }
345
d0d66c44 346 /* validate that we do not go past end of acl */
af6f4612 347 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
b6b38f70 348 cERROR(1, "ACL too small to parse DACL");
d0d66c44
SP
349 return;
350 }
351
b6b38f70 352 cFYI(DBG2, "DACL revision %d size %d num aces %d",
af6f4612 353 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
b6b38f70 354 le32_to_cpu(pdacl->num_aces));
d0d66c44 355
7505e052
SF
356 /* reset rwx permissions for user/group/other.
357 Also, if num_aces is 0 i.e. DACL has no ACEs,
358 user/group/other have no permissions */
0b8f18e3 359 fattr->cf_mode &= ~(S_IRWXUGO);
7505e052 360
d0d66c44
SP
361 acl_base = (char *)pdacl;
362 acl_size = sizeof(struct cifs_acl);
363
adbc0358 364 num_aces = le32_to_cpu(pdacl->num_aces);
d0d66c44 365 if (num_aces > 0) {
15b03959
SF
366 umode_t user_mask = S_IRWXU;
367 umode_t group_mask = S_IRWXG;
368 umode_t other_mask = S_IRWXO;
369
d0d66c44
SP
370 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
371 GFP_KERNEL);
372
d0d66c44 373 for (i = 0; i < num_aces; ++i) {
44093ca2 374 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
375#ifdef CONFIG_CIFS_DEBUG2
376 dump_ace(ppace[i], end_of_acl);
377#endif
e01b6400
SP
378 if (compare_sids(&(ppace[i]->sid), pownersid))
379 access_flags_to_mode(ppace[i]->access_req,
15b03959 380 ppace[i]->type,
0b8f18e3 381 &fattr->cf_mode,
15b03959 382 &user_mask);
e01b6400
SP
383 if (compare_sids(&(ppace[i]->sid), pgrpsid))
384 access_flags_to_mode(ppace[i]->access_req,
15b03959 385 ppace[i]->type,
0b8f18e3 386 &fattr->cf_mode,
15b03959 387 &group_mask);
e01b6400
SP
388 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
389 access_flags_to_mode(ppace[i]->access_req,
15b03959 390 ppace[i]->type,
0b8f18e3 391 &fattr->cf_mode,
15b03959 392 &other_mask);
e01b6400 393
44093ca2 394/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
395 (void *)ppace[i],
396 sizeof(struct cifs_ace)); */
d0d66c44 397
44093ca2
SF
398 acl_base = (char *)ppace[i];
399 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
400 }
401
402 kfree(ppace);
d0d66c44
SP
403 }
404
405 return;
406}
407
bcb02034 408
97837582
SF
409static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
410 struct cifs_sid *pgrpsid, __u64 nmode)
411{
2b210adc 412 u16 size = 0;
97837582
SF
413 struct cifs_acl *pnndacl;
414
415 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
416
417 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
418 pownersid, nmode, S_IRWXU);
419 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
420 pgrpsid, nmode, S_IRWXG);
421 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
422 &sid_everyone, nmode, S_IRWXO);
423
424 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
d9f382ef 425 pndacl->num_aces = cpu_to_le32(3);
97837582 426
ef571cad 427 return 0;
97837582
SF
428}
429
430
bcb02034
SF
431static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
432{
433 /* BB need to add parm so we can store the SID BB */
434
b9c7a2bb
SF
435 /* validate that we do not go past end of ACL - sid must be at least 8
436 bytes long (assuming no sub-auths - e.g. the null SID */
437 if (end_of_acl < (char *)psid + 8) {
b6b38f70 438 cERROR(1, "ACL too small to parse SID %p", psid);
bcb02034
SF
439 return -EINVAL;
440 }
d0d66c44 441
af6f4612 442 if (psid->num_subauth) {
bcb02034 443#ifdef CONFIG_CIFS_DEBUG2
8f18c131 444 int i;
b6b38f70
JP
445 cFYI(1, "SID revision %d num_auth %d",
446 psid->revision, psid->num_subauth);
bcb02034 447
af6f4612 448 for (i = 0; i < psid->num_subauth; i++) {
b6b38f70
JP
449 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
450 le32_to_cpu(psid->sub_auth[i]));
d0d66c44
SP
451 }
452
d12fd121 453 /* BB add length check to make sure that we do not have huge
d0d66c44 454 num auths and therefore go off the end */
b6b38f70
JP
455 cFYI(1, "RID 0x%x",
456 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
bcb02034 457#endif
d0d66c44
SP
458 }
459
bcb02034
SF
460 return 0;
461}
462
d0d66c44 463
bcb02034 464/* Convert CIFS ACL to POSIX form */
630f3f0c 465static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
0b8f18e3 466 struct cifs_fattr *fattr)
bcb02034 467{
d0d66c44 468 int rc;
bcb02034
SF
469 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
470 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 471 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 472 __u32 dacloffset;
bcb02034 473
0b8f18e3 474 if (pntsd == NULL)
b9c7a2bb
SF
475 return -EIO;
476
bcb02034 477 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 478 le32_to_cpu(pntsd->osidoffset));
bcb02034 479 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 480 le32_to_cpu(pntsd->gsidoffset));
7505e052 481 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 482 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
b6b38f70 483 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
bcb02034 484 "sacloffset 0x%x dacloffset 0x%x",
af6f4612
SF
485 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
486 le32_to_cpu(pntsd->gsidoffset),
b6b38f70 487 le32_to_cpu(pntsd->sacloffset), dacloffset);
b9c7a2bb 488/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034
SF
489 rc = parse_sid(owner_sid_ptr, end_of_acl);
490 if (rc)
491 return rc;
492
493 rc = parse_sid(group_sid_ptr, end_of_acl);
494 if (rc)
495 return rc;
496
7505e052
SF
497 if (dacloffset)
498 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
0b8f18e3 499 group_sid_ptr, fattr);
7505e052 500 else
b6b38f70 501 cFYI(1, "no ACL"); /* BB grant all or default perms? */
d0d66c44 502
bcb02034
SF
503/* cifscred->uid = owner_sid_ptr->rid;
504 cifscred->gid = group_sid_ptr->rid;
505 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
630f3f0c 506 sizeof(struct cifs_sid));
bcb02034 507 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
630f3f0c 508 sizeof(struct cifs_sid)); */
bcb02034 509
ef571cad 510 return 0;
bcb02034 511}
b9c7a2bb
SF
512
513
97837582
SF
514/* Convert permission bits from mode to equivalent CIFS ACL */
515static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
cce246ee 516 struct inode *inode, __u64 nmode)
97837582
SF
517{
518 int rc = 0;
519 __u32 dacloffset;
520 __u32 ndacloffset;
521 __u32 sidsoffset;
522 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
523 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
524 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
525
526 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
ef571cad 527 return -EIO;
97837582
SF
528
529 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
530 le32_to_cpu(pntsd->osidoffset));
531 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
532 le32_to_cpu(pntsd->gsidoffset));
533
534 dacloffset = le32_to_cpu(pntsd->dacloffset);
535 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
536
537 ndacloffset = sizeof(struct cifs_ntsd);
538 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
539 ndacl_ptr->revision = dacl_ptr->revision;
540 ndacl_ptr->size = 0;
541 ndacl_ptr->num_aces = 0;
542
543 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
544
545 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
546
547 /* copy security descriptor control portion and owner and group sid */
548 copy_sec_desc(pntsd, pnntsd, sidsoffset);
549
ef571cad 550 return rc;
97837582
SF
551}
552
1bf4072d
CH
553static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
554 __u16 fid, u32 *pacllen)
b9c7a2bb 555{
b9c7a2bb 556 struct cifs_ntsd *pntsd = NULL;
1bf4072d 557 int xid, rc;
7ffec372
JL
558 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
559
560 if (IS_ERR(tlink))
987b21d7 561 return ERR_CAST(tlink);
b9c7a2bb 562
1bf4072d 563 xid = GetXid();
7ffec372 564 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
1bf4072d 565 FreeXid(xid);
b9c7a2bb 566
7ffec372 567 cifs_put_tlink(tlink);
b9c7a2bb 568
987b21d7
SP
569 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
570 if (rc)
571 return ERR_PTR(rc);
1bf4072d
CH
572 return pntsd;
573}
8b1327f6 574
1bf4072d
CH
575static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
576 const char *path, u32 *pacllen)
577{
578 struct cifs_ntsd *pntsd = NULL;
579 int oplock = 0;
580 int xid, rc;
581 __u16 fid;
7ffec372
JL
582 struct cifsTconInfo *tcon;
583 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
584
585 if (IS_ERR(tlink))
987b21d7 586 return ERR_CAST(tlink);
b9c7a2bb 587
7ffec372 588 tcon = tlink_tcon(tlink);
1bf4072d
CH
589 xid = GetXid();
590
7ffec372 591 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
1bf4072d
CH
592 &fid, &oplock, NULL, cifs_sb->local_nls,
593 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
987b21d7
SP
594 if (!rc) {
595 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
596 CIFSSMBClose(xid, tcon, fid);
b9c7a2bb
SF
597 }
598
7ffec372 599 cifs_put_tlink(tlink);
7505e052 600 FreeXid(xid);
987b21d7
SP
601
602 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
603 if (rc)
604 return ERR_PTR(rc);
7505e052
SF
605 return pntsd;
606}
607
1bf4072d 608/* Retrieve an ACL from the server */
fbeba8bb 609struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1bf4072d
CH
610 struct inode *inode, const char *path,
611 u32 *pacllen)
612{
613 struct cifs_ntsd *pntsd = NULL;
614 struct cifsFileInfo *open_file = NULL;
615
616 if (inode)
6508d904 617 open_file = find_readable_file(CIFS_I(inode), true);
1bf4072d
CH
618 if (!open_file)
619 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
620
621 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
6ab409b5 622 cifsFileInfo_put(open_file);
1bf4072d
CH
623 return pntsd;
624}
625
b96d31a6
CH
626static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
627 struct cifs_ntsd *pnntsd, u32 acllen)
97837582 628{
b96d31a6 629 int xid, rc;
7ffec372
JL
630 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
631
632 if (IS_ERR(tlink))
633 return PTR_ERR(tlink);
97837582 634
b96d31a6 635 xid = GetXid();
7ffec372 636 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
b96d31a6 637 FreeXid(xid);
7ffec372 638 cifs_put_tlink(tlink);
97837582 639
b6b38f70 640 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
b96d31a6
CH
641 return rc;
642}
97837582 643
b96d31a6
CH
644static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
645 struct cifs_ntsd *pnntsd, u32 acllen)
646{
647 int oplock = 0;
648 int xid, rc;
649 __u16 fid;
7ffec372
JL
650 struct cifsTconInfo *tcon;
651 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
97837582 652
7ffec372
JL
653 if (IS_ERR(tlink))
654 return PTR_ERR(tlink);
655
656 tcon = tlink_tcon(tlink);
97837582
SF
657 xid = GetXid();
658
7ffec372 659 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
b96d31a6
CH
660 &fid, &oplock, NULL, cifs_sb->local_nls,
661 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
662 if (rc) {
b6b38f70 663 cERROR(1, "Unable to open file to set ACL");
b96d31a6 664 goto out;
97837582
SF
665 }
666
7ffec372 667 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
b6b38f70 668 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
97837582 669
7ffec372
JL
670 CIFSSMBClose(xid, tcon, fid);
671out:
97837582 672 FreeXid(xid);
7ffec372 673 cifs_put_tlink(tlink);
b96d31a6
CH
674 return rc;
675}
97837582 676
b96d31a6
CH
677/* Set an ACL on the server */
678static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
679 struct inode *inode, const char *path)
680{
681 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
682 struct cifsFileInfo *open_file;
683 int rc;
684
b6b38f70 685 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
b96d31a6 686
6508d904 687 open_file = find_readable_file(CIFS_I(inode), true);
b96d31a6
CH
688 if (!open_file)
689 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
690
691 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
6ab409b5 692 cifsFileInfo_put(open_file);
ef571cad 693 return rc;
97837582
SF
694}
695
7505e052 696/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
987b21d7 697int
0b8f18e3
JL
698cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
699 struct inode *inode, const char *path, const __u16 *pfid)
7505e052
SF
700{
701 struct cifs_ntsd *pntsd = NULL;
702 u32 acllen = 0;
703 int rc = 0;
704
b6b38f70 705 cFYI(DBG2, "converting ACL to mode for %s", path);
1bf4072d
CH
706
707 if (pfid)
708 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
709 else
710 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
7505e052
SF
711
712 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
987b21d7
SP
713 if (IS_ERR(pntsd)) {
714 rc = PTR_ERR(pntsd);
715 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
716 } else {
0b8f18e3 717 rc = parse_sec_desc(pntsd, acllen, fattr);
987b21d7
SP
718 kfree(pntsd);
719 if (rc)
720 cERROR(1, "parse sec desc failed rc = %d", rc);
721 }
7505e052 722
987b21d7 723 return rc;
b9c7a2bb 724}
953f8681 725
7505e052 726/* Convert mode bits to an ACL so we can update the ACL on the server */
78415d2d 727int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
953f8681
SF
728{
729 int rc = 0;
cce246ee 730 __u32 secdesclen = 0;
97837582
SF
731 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
732 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
953f8681 733
b6b38f70 734 cFYI(DBG2, "set ACL from mode for %s", path);
953f8681
SF
735
736 /* Get the security descriptor */
1bf4072d 737 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
953f8681 738
97837582
SF
739 /* Add three ACEs for owner, group, everyone getting rid of
740 other ACEs as chmod disables ACEs and set the security descriptor */
953f8681 741
987b21d7
SP
742 if (IS_ERR(pntsd)) {
743 rc = PTR_ERR(pntsd);
744 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
745 } else {
97837582
SF
746 /* allocate memory for the smb header,
747 set security descriptor request security descriptor
748 parameters, and secuirty descriptor itself */
953f8681 749
cce246ee
SF
750 secdesclen = secdesclen < DEFSECDESCLEN ?
751 DEFSECDESCLEN : secdesclen;
752 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
97837582 753 if (!pnntsd) {
b6b38f70 754 cERROR(1, "Unable to allocate security descriptor");
97837582 755 kfree(pntsd);
ef571cad 756 return -ENOMEM;
97837582 757 }
7505e052 758
cce246ee 759 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
97837582 760
b6b38f70 761 cFYI(DBG2, "build_sec_desc rc: %d", rc);
97837582
SF
762
763 if (!rc) {
764 /* Set the security descriptor */
cce246ee 765 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
b6b38f70 766 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
97837582
SF
767 }
768
769 kfree(pnntsd);
770 kfree(pntsd);
771 }
772
ef571cad 773 return rc;
953f8681 774}