blob: beeebf194234c4532341eaea45c316fe6cb58c3f [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 French630f3f02007-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 French630f3f02007-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 French630f3f02007-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);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300375 if (!ppace) {
376 cERROR(1, "DACL memory allocation error");
377 return;
378 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000379
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000380 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000381 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000382#ifdef CONFIG_CIFS_DEBUG2
383 dump_ace(ppace[i], end_of_acl);
384#endif
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000385 if (compare_sids(&(ppace[i]->sid), pownersid))
386 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000387 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400388 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000389 &user_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000390 if (compare_sids(&(ppace[i]->sid), pgrpsid))
391 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000392 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400393 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000394 &group_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000395 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
396 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000397 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400398 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000399 &other_mask);
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600400 if (compare_sids(&(ppace[i]->sid), &sid_authusers))
401 access_flags_to_mode(ppace[i]->access_req,
402 ppace[i]->type,
403 &fattr->cf_mode,
404 &other_mask);
405
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000406
Steve French44093ca2007-10-23 21:22:55 +0000407/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000408 (void *)ppace[i],
409 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000410
Steve French44093ca2007-10-23 21:22:55 +0000411 acl_base = (char *)ppace[i];
412 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000413 }
414
415 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000416 }
417
418 return;
419}
420
Steve Frenchbcb02032007-09-25 16:17:24 +0000421
Steve French97837582007-12-31 07:47:21 +0000422static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
423 struct cifs_sid *pgrpsid, __u64 nmode)
424{
Al Viro2b210ad2008-03-29 03:09:18 +0000425 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000426 struct cifs_acl *pnndacl;
427
428 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
429
430 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
431 pownersid, nmode, S_IRWXU);
432 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
433 pgrpsid, nmode, S_IRWXG);
434 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
435 &sid_everyone, nmode, S_IRWXO);
436
437 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000438 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000439
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000440 return 0;
Steve French97837582007-12-31 07:47:21 +0000441}
442
443
Steve Frenchbcb02032007-09-25 16:17:24 +0000444static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
445{
446 /* BB need to add parm so we can store the SID BB */
447
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000448 /* validate that we do not go past end of ACL - sid must be at least 8
449 bytes long (assuming no sub-auths - e.g. the null SID */
450 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000451 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000452 return -EINVAL;
453 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000454
Steve Frenchaf6f4612007-10-16 18:40:37 +0000455 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000456#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000457 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000458 cFYI(1, "SID revision %d num_auth %d",
459 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000460
Steve Frenchaf6f4612007-10-16 18:40:37 +0000461 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000462 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
463 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000464 }
465
Steve Frenchd12fd122007-10-03 19:43:19 +0000466 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000467 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000468 cFYI(1, "RID 0x%x",
469 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +0000470#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000471 }
472
Steve Frenchbcb02032007-09-25 16:17:24 +0000473 return 0;
474}
475
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000476
Steve Frenchbcb02032007-09-25 16:17:24 +0000477/* Convert CIFS ACL to POSIX form */
Steve French630f3f02007-10-25 21:17:17 +0000478static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400479 struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000480{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000481 int rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000482 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
483 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000484 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000485 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000486
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400487 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000488 return -EIO;
489
Steve Frenchbcb02032007-09-25 16:17:24 +0000490 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000491 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000492 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000493 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000494 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000495 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000496 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000497 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000498 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
499 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000500 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000501/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000502 rc = parse_sid(owner_sid_ptr, end_of_acl);
503 if (rc)
504 return rc;
505
506 rc = parse_sid(group_sid_ptr, end_of_acl);
507 if (rc)
508 return rc;
509
Steve French7505e052007-11-01 18:03:01 +0000510 if (dacloffset)
511 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400512 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000513 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000514 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000515
Steve Frenchbcb02032007-09-25 16:17:24 +0000516/* cifscred->uid = owner_sid_ptr->rid;
517 cifscred->gid = group_sid_ptr->rid;
518 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f02007-10-25 21:17:17 +0000519 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000520 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f02007-10-25 21:17:17 +0000521 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000522
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000523 return 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000524}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000525
526
Steve French97837582007-12-31 07:47:21 +0000527/* Convert permission bits from mode to equivalent CIFS ACL */
528static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve Frenchcce246e2008-04-09 20:55:31 +0000529 struct inode *inode, __u64 nmode)
Steve French97837582007-12-31 07:47:21 +0000530{
531 int rc = 0;
532 __u32 dacloffset;
533 __u32 ndacloffset;
534 __u32 sidsoffset;
535 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
536 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
537 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
538
539 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000540 return -EIO;
Steve French97837582007-12-31 07:47:21 +0000541
542 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
543 le32_to_cpu(pntsd->osidoffset));
544 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
545 le32_to_cpu(pntsd->gsidoffset));
546
547 dacloffset = le32_to_cpu(pntsd->dacloffset);
548 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
549
550 ndacloffset = sizeof(struct cifs_ntsd);
551 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
552 ndacl_ptr->revision = dacl_ptr->revision;
553 ndacl_ptr->size = 0;
554 ndacl_ptr->num_aces = 0;
555
556 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
557
558 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
559
560 /* copy security descriptor control portion and owner and group sid */
561 copy_sec_desc(pntsd, pnntsd, sidsoffset);
562
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000563 return rc;
Steve French97837582007-12-31 07:47:21 +0000564}
565
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400566static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
567 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000568{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000569 struct cifs_ntsd *pntsd = NULL;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400570 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400571 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
572
573 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600574 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000575
576 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400577 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400578 FreeXid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000579
Jeff Layton7ffec372010-09-29 19:51:11 -0400580 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000581
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600582 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
583 if (rc)
584 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400585 return pntsd;
586}
587
588static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
589 const char *path, u32 *pacllen)
590{
591 struct cifs_ntsd *pntsd = NULL;
592 int oplock = 0;
593 int xid, rc;
594 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400595 struct cifsTconInfo *tcon;
596 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400597
Jeff Layton7ffec372010-09-29 19:51:11 -0400598 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600599 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400600
601 tcon = tlink_tcon(tlink);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400602 xid = GetXid();
603
Jeff Layton7ffec372010-09-29 19:51:11 -0400604 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400605 &fid, &oplock, NULL, cifs_sb->local_nls,
606 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600607 if (!rc) {
608 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
609 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000610 }
611
Jeff Layton7ffec372010-09-29 19:51:11 -0400612 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000613 FreeXid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600614
615 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
616 if (rc)
617 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000618 return pntsd;
619}
620
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400621/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600622struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400623 struct inode *inode, const char *path,
624 u32 *pacllen)
625{
626 struct cifs_ntsd *pntsd = NULL;
627 struct cifsFileInfo *open_file = NULL;
628
629 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400630 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400631 if (!open_file)
632 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
633
634 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400635 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400636 return pntsd;
637}
638
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400639static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
640 struct cifs_ntsd *pnntsd, u32 acllen)
Steve French97837582007-12-31 07:47:21 +0000641{
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400642 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400643 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
644
645 if (IS_ERR(tlink))
646 return PTR_ERR(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400647
648 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400649 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400650 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400651 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400652
Joe Perchesb6b38f72010-04-21 03:50:45 +0000653 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400654 return rc;
655}
656
657static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
658 struct cifs_ntsd *pnntsd, u32 acllen)
659{
660 int oplock = 0;
661 int xid, rc;
Steve French97837582007-12-31 07:47:21 +0000662 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400663 struct cifsTconInfo *tcon;
664 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000665
Jeff Layton7ffec372010-09-29 19:51:11 -0400666 if (IS_ERR(tlink))
667 return PTR_ERR(tlink);
668
669 tcon = tlink_tcon(tlink);
Steve French97837582007-12-31 07:47:21 +0000670 xid = GetXid();
671
Jeff Layton7ffec372010-09-29 19:51:11 -0400672 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400673 &fid, &oplock, NULL, cifs_sb->local_nls,
674 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
675 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400677 goto out;
Steve French97837582007-12-31 07:47:21 +0000678 }
679
Jeff Layton7ffec372010-09-29 19:51:11 -0400680 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000681 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000682
Jeff Layton7ffec372010-09-29 19:51:11 -0400683 CIFSSMBClose(xid, tcon, fid);
684out:
Steve French97837582007-12-31 07:47:21 +0000685 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400686 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400687 return rc;
688}
Steve French97837582007-12-31 07:47:21 +0000689
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400690/* Set an ACL on the server */
691static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
692 struct inode *inode, const char *path)
693{
694 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
695 struct cifsFileInfo *open_file;
696 int rc;
697
Joe Perchesb6b38f72010-04-21 03:50:45 +0000698 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400699
Jeff Layton6508d902010-09-29 19:51:11 -0400700 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400701 if (!open_file)
702 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
703
704 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400705 cifsFileInfo_put(open_file);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000706 return rc;
Steve French97837582007-12-31 07:47:21 +0000707}
708
Steve French7505e052007-11-01 18:03:01 +0000709/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600710int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400711cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
712 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000713{
714 struct cifs_ntsd *pntsd = NULL;
715 u32 acllen = 0;
716 int rc = 0;
717
Joe Perchesb6b38f72010-04-21 03:50:45 +0000718 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400719
720 if (pfid)
721 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
722 else
723 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000724
725 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600726 if (IS_ERR(pntsd)) {
727 rc = PTR_ERR(pntsd);
728 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
729 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400730 rc = parse_sec_desc(pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600731 kfree(pntsd);
732 if (rc)
733 cERROR(1, "parse sec desc failed rc = %d", rc);
734 }
Steve French7505e052007-11-01 18:03:01 +0000735
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600736 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000737}
Steve French953f8682007-10-31 04:54:42 +0000738
Steve French7505e052007-11-01 18:03:01 +0000739/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkar78415d22010-11-27 11:37:26 -0600740int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
Steve French953f8682007-10-31 04:54:42 +0000741{
742 int rc = 0;
Steve Frenchcce246e2008-04-09 20:55:31 +0000743 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +0000744 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
745 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +0000746
Joe Perchesb6b38f72010-04-21 03:50:45 +0000747 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +0000748
749 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400750 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +0000751
Steve French97837582007-12-31 07:47:21 +0000752 /* Add three ACEs for owner, group, everyone getting rid of
753 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +0000754
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600755 if (IS_ERR(pntsd)) {
756 rc = PTR_ERR(pntsd);
757 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
758 } else {
Steve French97837582007-12-31 07:47:21 +0000759 /* allocate memory for the smb header,
760 set security descriptor request security descriptor
761 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +0000762
Steve Frenchcce246e2008-04-09 20:55:31 +0000763 secdesclen = secdesclen < DEFSECDESCLEN ?
764 DEFSECDESCLEN : secdesclen;
765 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +0000766 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000767 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +0000768 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000769 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +0000770 }
Steve French7505e052007-11-01 18:03:01 +0000771
Steve Frenchcce246e2008-04-09 20:55:31 +0000772 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
Steve French97837582007-12-31 07:47:21 +0000773
Joe Perchesb6b38f72010-04-21 03:50:45 +0000774 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +0000775
776 if (!rc) {
777 /* Set the security descriptor */
Steve Frenchcce246e2008-04-09 20:55:31 +0000778 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000779 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +0000780 }
781
782 kfree(pnntsd);
783 kfree(pntsd);
784 }
785
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000786 return rc;
Steve French953f8682007-10-31 04:54:42 +0000787}