blob: 1e7636b145a88a180c8459f65bf86d51d6c165f6 [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
Steve French8b1327f2008-03-14 22:37:16 +00004 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00005 * 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
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Steve French65874002007-09-25 19:53:44 +000026#include "cifspdu.h"
27#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000028#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000029#include "cifsproto.h"
30#include "cifs_debug.h"
Steve French65874002007-09-25 19:53:44 +000031
Steve French297647c2007-10-12 04:11:59 +000032
Steve Frenchaf6f4612007-10-16 18:40:37 +000033static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
Steve French297647c2007-10-12 04:11:59 +000034 {{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"},
Jeff Layton536abdb2008-07-12 13:48:00 -070036 {{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"} }
Steve French44093ca2007-10-23 21:22:55 +000041;
Steve French297647c2007-10-12 04:11:59 +000042
43
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060044/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000045static const struct cifs_sid sid_everyone = {
46 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060047/* security id for Authenticated Users system group */
48static const struct cifs_sid sid_authusers = {
49 1, 1, {0, 0, 0, 0, 0, 5}, {11} };
Steve Frenchbcb02032007-09-25 16:17:24 +000050/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000051static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000052
Steve French297647c2007-10-12 04:11:59 +000053
54int match_sid(struct cifs_sid *ctsid)
55{
56 int i, j;
57 int num_subauth, num_sat, num_saw;
58 struct cifs_sid *cwsid;
59
60 if (!ctsid)
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +000061 return -1;
Steve French297647c2007-10-12 04:11:59 +000062
63 for (i = 0; i < NUM_WK_SIDS; ++i) {
64 cwsid = &(wksidarr[i].cifssid);
65
66 /* compare the revision */
67 if (ctsid->revision != cwsid->revision)
68 continue;
69
70 /* compare all of the six auth values */
71 for (j = 0; j < 6; ++j) {
72 if (ctsid->authority[j] != cwsid->authority[j])
73 break;
74 }
75 if (j < 6)
76 continue; /* all of the auth values did not match */
77
78 /* compare all of the subauth values if any */
Dave Kleikampce51ae12007-10-16 21:35:39 +000079 num_sat = ctsid->num_subauth;
80 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +000081 num_subauth = num_sat < num_saw ? num_sat : num_saw;
82 if (num_subauth) {
83 for (j = 0; j < num_subauth; ++j) {
84 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
85 break;
86 }
87 if (j < num_subauth)
88 continue; /* all sub_auth values do not match */
89 }
90
Joe Perchesb6b38f72010-04-21 03:50:45 +000091 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +000092 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +000093 }
94
Joe Perchesb6b38f72010-04-21 03:50:45 +000095 cFYI(1, "No matching sid");
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +000096 return -1;
Steve French297647c2007-10-12 04:11:59 +000097}
98
Steve Frencha750e772007-10-17 22:50:39 +000099/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
100 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000101int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000102{
103 int i;
104 int num_subauth, num_sat, num_saw;
105
106 if ((!ctsid) || (!cwsid))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000107 return 0;
Steve French297647c2007-10-12 04:11:59 +0000108
109 /* compare the revision */
110 if (ctsid->revision != cwsid->revision)
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000111 return 0;
Steve French297647c2007-10-12 04:11:59 +0000112
113 /* compare all of the six auth values */
114 for (i = 0; i < 6; ++i) {
115 if (ctsid->authority[i] != cwsid->authority[i])
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000116 return 0;
Steve French297647c2007-10-12 04:11:59 +0000117 }
118
119 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000120 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000121 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000122 num_subauth = num_sat < num_saw ? num_sat : num_saw;
123 if (num_subauth) {
124 for (i = 0; i < num_subauth; ++i) {
125 if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000126 return 0;
Steve French297647c2007-10-12 04:11:59 +0000127 }
128 }
129
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000130 return 1; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000131}
132
Steve French97837582007-12-31 07:47:21 +0000133
134/* copy ntsd, owner sid, and group sid from a security descriptor to another */
135static void copy_sec_desc(const struct cifs_ntsd *pntsd,
136 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
137{
138 int i;
139
140 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
141 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
142
143 /* copy security descriptor control portion */
144 pnntsd->revision = pntsd->revision;
145 pnntsd->type = pntsd->type;
146 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
147 pnntsd->sacloffset = 0;
148 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
149 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
150
151 /* copy owner sid */
152 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
153 le32_to_cpu(pntsd->osidoffset));
154 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
155
156 nowner_sid_ptr->revision = owner_sid_ptr->revision;
157 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
158 for (i = 0; i < 6; i++)
159 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
160 for (i = 0; i < 5; i++)
161 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
162
163 /* copy group sid */
164 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
165 le32_to_cpu(pntsd->gsidoffset));
166 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
167 sizeof(struct cifs_sid));
168
169 ngroup_sid_ptr->revision = group_sid_ptr->revision;
170 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
171 for (i = 0; i < 6; i++)
172 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
173 for (i = 0; i < 5; i++)
Shirish Pargaonkarb1910ad2008-07-24 14:53:20 +0000174 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
Steve French97837582007-12-31 07:47:21 +0000175
176 return;
177}
178
179
Steve French630f3f0c2007-10-25 21:17:17 +0000180/*
181 change posix mode to reflect permissions
182 pmode is the existing mode (we only want to overwrite part of this
183 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
184*/
Al Viro9b5e6852007-12-05 08:24:38 +0000185static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000186 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000187{
Al Viro9b5e6852007-12-05 08:24:38 +0000188 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000189 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000190 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000191 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000192 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000193 for the operation you are trying to perform for your user */
194
195 /* For deny ACEs we change the mask so that subsequent allow access
196 control entries do not turn on the bits we are denying */
197 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000198 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000199 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000200
Al Viro9b5e6852007-12-05 08:24:38 +0000201 if ((flags & GENERIC_WRITE) ||
202 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000203 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000204 if ((flags & GENERIC_READ) ||
205 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000206 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000207 if ((flags & GENERIC_EXECUTE) ||
208 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000209 *pbits_to_set &= ~S_IXUGO;
210 return;
211 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000212 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000213 return;
214 }
215 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000216
Al Viro9b5e6852007-12-05 08:24:38 +0000217 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000218 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000219 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000220 return;
221 }
Al Viro9b5e6852007-12-05 08:24:38 +0000222 if ((flags & GENERIC_WRITE) ||
223 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000224 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000225 if ((flags & GENERIC_READ) ||
226 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000227 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000228 if ((flags & GENERIC_EXECUTE) ||
229 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000230 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000231
Joe Perchesb6b38f72010-04-21 03:50:45 +0000232 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000233 return;
234}
235
Steve Frenchce06c9f2007-11-08 21:12:01 +0000236/*
237 Generate access flags to reflect permissions mode is the existing mode.
238 This function is called for every ACE in the DACL whose SID matches
239 with either owner or group or everyone.
240*/
241
242static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
243 __u32 *pace_flags)
244{
245 /* reset access mask */
246 *pace_flags = 0x0;
247
248 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
249 mode &= bits_to_use;
250
251 /* check for R/W/X UGO since we do not know whose flags
252 is this but we have cleared all the bits sans RWX for
253 either user or group or other as per bits_to_use */
254 if (mode & S_IRUGO)
255 *pace_flags |= SET_FILE_READ_RIGHTS;
256 if (mode & S_IWUGO)
257 *pace_flags |= SET_FILE_WRITE_RIGHTS;
258 if (mode & S_IXUGO)
259 *pace_flags |= SET_FILE_EXEC_RIGHTS;
260
Joe Perchesb6b38f72010-04-21 03:50:45 +0000261 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000262 return;
263}
264
Al Viro2b210ad2008-03-29 03:09:18 +0000265static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000266 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
267{
268 int i;
269 __u16 size = 0;
270 __u32 access_req = 0;
271
272 pntace->type = ACCESS_ALLOWED;
273 pntace->flags = 0x0;
274 mode_to_access_flags(nmode, bits, &access_req);
275 if (!access_req)
276 access_req = SET_MINIMUM_RIGHTS;
277 pntace->access_req = cpu_to_le32(access_req);
278
279 pntace->sid.revision = psid->revision;
280 pntace->sid.num_subauth = psid->num_subauth;
281 for (i = 0; i < 6; i++)
282 pntace->sid.authority[i] = psid->authority[i];
283 for (i = 0; i < psid->num_subauth; i++)
284 pntace->sid.sub_auth[i] = psid->sub_auth[i];
285
286 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
287 pntace->size = cpu_to_le16(size);
288
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000289 return size;
Steve French97837582007-12-31 07:47:21 +0000290}
291
Steve French297647c2007-10-12 04:11:59 +0000292
Steve French953f8682007-10-31 04:54:42 +0000293#ifdef CONFIG_CIFS_DEBUG2
294static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000295{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000296 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000297
298 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000299
Steve French44093ca2007-10-23 21:22:55 +0000300 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000301 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000302 return;
303 }
304
305 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000306 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000307 return;
Steve French44093ca2007-10-23 21:22:55 +0000308 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000309
Steve French44093ca2007-10-23 21:22:55 +0000310 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000311 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000312 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000313 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000314 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000315 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000316 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000317 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
318 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000319 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000320
Steve Frenchd12fd122007-10-03 19:43:19 +0000321 /* BB add length check to make sure that we do not have huge
322 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000323 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000324
Steve Frenchd12fd122007-10-03 19:43:19 +0000325 return;
326}
Steve French953f8682007-10-31 04:54:42 +0000327#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000328
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000329
Steve Frencha750e772007-10-17 22:50:39 +0000330static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000331 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400332 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000333{
334 int i;
335 int num_aces = 0;
336 int acl_size;
337 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000338 struct cifs_ace **ppace;
339
340 /* BB need to add parm so we can store the SID BB */
341
Steve French2b834572007-11-25 10:01:00 +0000342 if (!pdacl) {
343 /* no DACL in the security descriptor, set
344 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400345 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000346 return;
347 }
348
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000349 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000350 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000351 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000352 return;
353 }
354
Joe Perchesb6b38f72010-04-21 03:50:45 +0000355 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000356 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000357 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000358
Steve French7505e052007-11-01 18:03:01 +0000359 /* reset rwx permissions for user/group/other.
360 Also, if num_aces is 0 i.e. DACL has no ACEs,
361 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400362 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000363
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000364 acl_base = (char *)pdacl;
365 acl_size = sizeof(struct cifs_acl);
366
Steve Frenchadbc0352007-10-17 02:12:46 +0000367 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000368 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000369 umode_t user_mask = S_IRWXU;
370 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600371 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000372
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000373 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
374 GFP_KERNEL);
375
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000376 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000377 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000378#ifdef CONFIG_CIFS_DEBUG2
379 dump_ace(ppace[i], end_of_acl);
380#endif
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000381 if (compare_sids(&(ppace[i]->sid), pownersid))
382 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000383 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400384 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000385 &user_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000386 if (compare_sids(&(ppace[i]->sid), pgrpsid))
387 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000388 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400389 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000390 &group_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000391 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
392 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000393 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400394 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000395 &other_mask);
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600396 if (compare_sids(&(ppace[i]->sid), &sid_authusers))
397 access_flags_to_mode(ppace[i]->access_req,
398 ppace[i]->type,
399 &fattr->cf_mode,
400 &other_mask);
401
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000402
Steve French44093ca2007-10-23 21:22:55 +0000403/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000404 (void *)ppace[i],
405 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000406
Steve French44093ca2007-10-23 21:22:55 +0000407 acl_base = (char *)ppace[i];
408 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000409 }
410
411 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000412 }
413
414 return;
415}
416
Steve Frenchbcb02032007-09-25 16:17:24 +0000417
Steve French97837582007-12-31 07:47:21 +0000418static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
419 struct cifs_sid *pgrpsid, __u64 nmode)
420{
Al Viro2b210ad2008-03-29 03:09:18 +0000421 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000422 struct cifs_acl *pnndacl;
423
424 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
425
426 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
427 pownersid, nmode, S_IRWXU);
428 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
429 pgrpsid, nmode, S_IRWXG);
430 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
431 &sid_everyone, nmode, S_IRWXO);
432
433 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000434 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000435
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000436 return 0;
Steve French97837582007-12-31 07:47:21 +0000437}
438
439
Steve Frenchbcb02032007-09-25 16:17:24 +0000440static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
441{
442 /* BB need to add parm so we can store the SID BB */
443
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000444 /* validate that we do not go past end of ACL - sid must be at least 8
445 bytes long (assuming no sub-auths - e.g. the null SID */
446 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000447 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000448 return -EINVAL;
449 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000450
Steve Frenchaf6f4612007-10-16 18:40:37 +0000451 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000452#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000453 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000454 cFYI(1, "SID revision %d num_auth %d",
455 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000456
Steve Frenchaf6f4612007-10-16 18:40:37 +0000457 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000458 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
459 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000460 }
461
Steve Frenchd12fd122007-10-03 19:43:19 +0000462 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000463 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000464 cFYI(1, "RID 0x%x",
465 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +0000466#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000467 }
468
Steve Frenchbcb02032007-09-25 16:17:24 +0000469 return 0;
470}
471
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000472
Steve Frenchbcb02032007-09-25 16:17:24 +0000473/* Convert CIFS ACL to POSIX form */
Steve French630f3f0c2007-10-25 21:17:17 +0000474static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400475 struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000476{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000477 int rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000478 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
479 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000480 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000481 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000482
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400483 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000484 return -EIO;
485
Steve Frenchbcb02032007-09-25 16:17:24 +0000486 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000487 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000488 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000489 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000490 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000491 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000492 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000493 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000494 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
495 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000496 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000497/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000498 rc = parse_sid(owner_sid_ptr, end_of_acl);
499 if (rc)
500 return rc;
501
502 rc = parse_sid(group_sid_ptr, end_of_acl);
503 if (rc)
504 return rc;
505
Steve French7505e052007-11-01 18:03:01 +0000506 if (dacloffset)
507 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400508 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000509 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000510 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000511
Steve Frenchbcb02032007-09-25 16:17:24 +0000512/* cifscred->uid = owner_sid_ptr->rid;
513 cifscred->gid = group_sid_ptr->rid;
514 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000515 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000516 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000517 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000518
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000519 return 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000520}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000521
522
Steve French97837582007-12-31 07:47:21 +0000523/* Convert permission bits from mode to equivalent CIFS ACL */
524static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve Frenchcce246e2008-04-09 20:55:31 +0000525 struct inode *inode, __u64 nmode)
Steve French97837582007-12-31 07:47:21 +0000526{
527 int rc = 0;
528 __u32 dacloffset;
529 __u32 ndacloffset;
530 __u32 sidsoffset;
531 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
532 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
533 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
534
535 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000536 return -EIO;
Steve French97837582007-12-31 07:47:21 +0000537
538 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
539 le32_to_cpu(pntsd->osidoffset));
540 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
541 le32_to_cpu(pntsd->gsidoffset));
542
543 dacloffset = le32_to_cpu(pntsd->dacloffset);
544 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
545
546 ndacloffset = sizeof(struct cifs_ntsd);
547 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
548 ndacl_ptr->revision = dacl_ptr->revision;
549 ndacl_ptr->size = 0;
550 ndacl_ptr->num_aces = 0;
551
552 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
553
554 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
555
556 /* copy security descriptor control portion and owner and group sid */
557 copy_sec_desc(pntsd, pnntsd, sidsoffset);
558
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000559 return rc;
Steve French97837582007-12-31 07:47:21 +0000560}
561
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400562static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
563 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000564{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000565 struct cifs_ntsd *pntsd = NULL;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400566 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400567 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
568
569 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600570 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000571
572 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400573 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400574 FreeXid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000575
Jeff Layton7ffec372010-09-29 19:51:11 -0400576 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000577
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600578 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
579 if (rc)
580 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400581 return pntsd;
582}
583
584static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
585 const char *path, u32 *pacllen)
586{
587 struct cifs_ntsd *pntsd = NULL;
588 int oplock = 0;
589 int xid, rc;
590 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400591 struct cifsTconInfo *tcon;
592 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400593
Jeff Layton7ffec372010-09-29 19:51:11 -0400594 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600595 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400596
597 tcon = tlink_tcon(tlink);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400598 xid = GetXid();
599
Jeff Layton7ffec372010-09-29 19:51:11 -0400600 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400601 &fid, &oplock, NULL, cifs_sb->local_nls,
602 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600603 if (!rc) {
604 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
605 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000606 }
607
Jeff Layton7ffec372010-09-29 19:51:11 -0400608 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000609 FreeXid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600610
611 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
612 if (rc)
613 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000614 return pntsd;
615}
616
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400617/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600618struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400619 struct inode *inode, const char *path,
620 u32 *pacllen)
621{
622 struct cifs_ntsd *pntsd = NULL;
623 struct cifsFileInfo *open_file = NULL;
624
625 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400626 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400627 if (!open_file)
628 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
629
630 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400631 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400632 return pntsd;
633}
634
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400635static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
636 struct cifs_ntsd *pnntsd, u32 acllen)
Steve French97837582007-12-31 07:47:21 +0000637{
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400638 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400639 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
640
641 if (IS_ERR(tlink))
642 return PTR_ERR(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400643
644 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400645 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400646 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400647 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400648
Joe Perchesb6b38f72010-04-21 03:50:45 +0000649 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400650 return rc;
651}
652
653static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
654 struct cifs_ntsd *pnntsd, u32 acllen)
655{
656 int oplock = 0;
657 int xid, rc;
Steve French97837582007-12-31 07:47:21 +0000658 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400659 struct cifsTconInfo *tcon;
660 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000661
Jeff Layton7ffec372010-09-29 19:51:11 -0400662 if (IS_ERR(tlink))
663 return PTR_ERR(tlink);
664
665 tcon = tlink_tcon(tlink);
Steve French97837582007-12-31 07:47:21 +0000666 xid = GetXid();
667
Jeff Layton7ffec372010-09-29 19:51:11 -0400668 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400669 &fid, &oplock, NULL, cifs_sb->local_nls,
670 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
671 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000672 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400673 goto out;
Steve French97837582007-12-31 07:47:21 +0000674 }
675
Jeff Layton7ffec372010-09-29 19:51:11 -0400676 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000677 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000678
Jeff Layton7ffec372010-09-29 19:51:11 -0400679 CIFSSMBClose(xid, tcon, fid);
680out:
Steve French97837582007-12-31 07:47:21 +0000681 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400682 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400683 return rc;
684}
Steve French97837582007-12-31 07:47:21 +0000685
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400686/* Set an ACL on the server */
687static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
688 struct inode *inode, const char *path)
689{
690 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
691 struct cifsFileInfo *open_file;
692 int rc;
693
Joe Perchesb6b38f72010-04-21 03:50:45 +0000694 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400695
Jeff Layton6508d902010-09-29 19:51:11 -0400696 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400697 if (!open_file)
698 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
699
700 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400701 cifsFileInfo_put(open_file);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000702 return rc;
Steve French97837582007-12-31 07:47:21 +0000703}
704
Steve French7505e052007-11-01 18:03:01 +0000705/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600706int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400707cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
708 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000709{
710 struct cifs_ntsd *pntsd = NULL;
711 u32 acllen = 0;
712 int rc = 0;
713
Joe Perchesb6b38f72010-04-21 03:50:45 +0000714 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400715
716 if (pfid)
717 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
718 else
719 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000720
721 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600722 if (IS_ERR(pntsd)) {
723 rc = PTR_ERR(pntsd);
724 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
725 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400726 rc = parse_sec_desc(pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600727 kfree(pntsd);
728 if (rc)
729 cERROR(1, "parse sec desc failed rc = %d", rc);
730 }
Steve French7505e052007-11-01 18:03:01 +0000731
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600732 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000733}
Steve French953f8682007-10-31 04:54:42 +0000734
Steve French7505e052007-11-01 18:03:01 +0000735/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkar78415d22010-11-27 11:37:26 -0600736int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
Steve French953f8682007-10-31 04:54:42 +0000737{
738 int rc = 0;
Steve Frenchcce246e2008-04-09 20:55:31 +0000739 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +0000740 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
741 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +0000742
Joe Perchesb6b38f72010-04-21 03:50:45 +0000743 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +0000744
745 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400746 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +0000747
Steve French97837582007-12-31 07:47:21 +0000748 /* Add three ACEs for owner, group, everyone getting rid of
749 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +0000750
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600751 if (IS_ERR(pntsd)) {
752 rc = PTR_ERR(pntsd);
753 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
754 } else {
Steve French97837582007-12-31 07:47:21 +0000755 /* allocate memory for the smb header,
756 set security descriptor request security descriptor
757 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +0000758
Steve Frenchcce246e2008-04-09 20:55:31 +0000759 secdesclen = secdesclen < DEFSECDESCLEN ?
760 DEFSECDESCLEN : secdesclen;
761 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +0000762 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000763 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +0000764 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000765 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +0000766 }
Steve French7505e052007-11-01 18:03:01 +0000767
Steve Frenchcce246e2008-04-09 20:55:31 +0000768 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
Steve French97837582007-12-31 07:47:21 +0000769
Joe Perchesb6b38f72010-04-21 03:50:45 +0000770 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +0000771
772 if (!rc) {
773 /* Set the security descriptor */
Steve Frenchcce246e2008-04-09 20:55:31 +0000774 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000775 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +0000776 }
777
778 kfree(pnntsd);
779 kfree(pntsd);
780 }
781
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000782 return rc;
Steve French953f8682007-10-31 04:54:42 +0000783}