blob: c312adcba4fc1b0530cba4e869beeca9763c13d3 [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
4 * Copyright (C) International Business Machines Corp., 2007
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
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
25#include "cifspdu.h"
26#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000027#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000028#include "cifsproto.h"
29#include "cifs_debug.h"
Steve French65874002007-09-25 19:53:44 +000030
Steve French297647c2007-10-12 04:11:59 +000031
32#ifdef CONFIG_CIFS_EXPERIMENTAL
33
Steve Frenchaf6f4612007-10-16 18:40:37 +000034static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
Steve French297647c2007-10-12 04:11:59 +000035 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
36 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
Dave Kleikampce51ae12007-10-16 21:35:39 +000037 {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
38 {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
39 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"},
40 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"},
Steve French44093ca2007-10-23 21:22:55 +000041 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }
42;
Steve French297647c2007-10-12 04:11:59 +000043
44
Steve Frenchbcb02032007-09-25 16:17:24 +000045/* security id for everyone */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000046static const struct cifs_sid sid_everyone = {
47 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Steve Frenchbcb02032007-09-25 16:17:24 +000048/* group users */
49static const struct cifs_sid sid_user =
Steve Frenchd12fd122007-10-03 19:43:19 +000050 {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000051
Steve French297647c2007-10-12 04:11:59 +000052
53int match_sid(struct cifs_sid *ctsid)
54{
55 int i, j;
56 int num_subauth, num_sat, num_saw;
57 struct cifs_sid *cwsid;
58
59 if (!ctsid)
60 return (-1);
61
62 for (i = 0; i < NUM_WK_SIDS; ++i) {
63 cwsid = &(wksidarr[i].cifssid);
64
65 /* compare the revision */
66 if (ctsid->revision != cwsid->revision)
67 continue;
68
69 /* compare all of the six auth values */
70 for (j = 0; j < 6; ++j) {
71 if (ctsid->authority[j] != cwsid->authority[j])
72 break;
73 }
74 if (j < 6)
75 continue; /* all of the auth values did not match */
76
77 /* compare all of the subauth values if any */
Dave Kleikampce51ae12007-10-16 21:35:39 +000078 num_sat = ctsid->num_subauth;
79 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +000080 num_subauth = num_sat < num_saw ? num_sat : num_saw;
81 if (num_subauth) {
82 for (j = 0; j < num_subauth; ++j) {
83 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
84 break;
85 }
86 if (j < num_subauth)
87 continue; /* all sub_auth values do not match */
88 }
89
90 cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname));
91 return (0); /* sids compare/match */
92 }
93
94 cFYI(1, ("No matching sid"));
95 return (-1);
96}
97
Steve Frencha750e772007-10-17 22:50:39 +000098/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
99 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000100int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000101{
102 int i;
103 int num_subauth, num_sat, num_saw;
104
105 if ((!ctsid) || (!cwsid))
Steve Frencha750e772007-10-17 22:50:39 +0000106 return (0);
Steve French297647c2007-10-12 04:11:59 +0000107
108 /* compare the revision */
109 if (ctsid->revision != cwsid->revision)
Steve Frencha750e772007-10-17 22:50:39 +0000110 return (0);
Steve French297647c2007-10-12 04:11:59 +0000111
112 /* compare all of the six auth values */
113 for (i = 0; i < 6; ++i) {
114 if (ctsid->authority[i] != cwsid->authority[i])
Steve Frencha750e772007-10-17 22:50:39 +0000115 return (0);
Steve French297647c2007-10-12 04:11:59 +0000116 }
117
118 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000119 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000120 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000121 num_subauth = num_sat < num_saw ? num_sat : num_saw;
122 if (num_subauth) {
123 for (i = 0; i < num_subauth; ++i) {
124 if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
Steve Frencha750e772007-10-17 22:50:39 +0000125 return (0);
Steve French297647c2007-10-12 04:11:59 +0000126 }
127 }
128
Steve Frencha750e772007-10-17 22:50:39 +0000129 return (1); /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000130}
131
Steve French630f3f0c2007-10-25 21:17:17 +0000132/*
133 change posix mode to reflect permissions
134 pmode is the existing mode (we only want to overwrite part of this
135 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
136*/
Al Viro9b5e6852007-12-05 08:24:38 +0000137static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000138 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000139{
Al Viro9b5e6852007-12-05 08:24:38 +0000140 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000141 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000142 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000143 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000144 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000145 for the operation you are trying to perform for your user */
146
147 /* For deny ACEs we change the mask so that subsequent allow access
148 control entries do not turn on the bits we are denying */
149 if (type == ACCESS_DENIED) {
Al Viro9b5e6852007-12-05 08:24:38 +0000150 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000151 *pbits_to_set &= ~S_IRWXUGO;
152 }
Al Viro9b5e6852007-12-05 08:24:38 +0000153 if ((flags & GENERIC_WRITE) ||
154 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000155 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000156 if ((flags & GENERIC_READ) ||
157 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000158 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000159 if ((flags & GENERIC_EXECUTE) ||
160 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000161 *pbits_to_set &= ~S_IXUGO;
162 return;
163 } else if (type != ACCESS_ALLOWED) {
164 cERROR(1, ("unknown access control type %d", type));
165 return;
166 }
167 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000168
Al Viro9b5e6852007-12-05 08:24:38 +0000169 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000170 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000171#ifdef CONFIG_CIFS_DEBUG2
172 cFYI(1, ("all perms"));
173#endif
174 return;
175 }
Al Viro9b5e6852007-12-05 08:24:38 +0000176 if ((flags & GENERIC_WRITE) ||
177 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000178 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000179 if ((flags & GENERIC_READ) ||
180 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000181 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000182 if ((flags & GENERIC_EXECUTE) ||
183 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000184 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000185
186#ifdef CONFIG_CIFS_DEBUG2
Al Viro9b5e6852007-12-05 08:24:38 +0000187 cFYI(1, ("access flags 0x%x mode now 0x%x", flags, *pmode));
Steve Frenchd61e5802007-10-26 04:32:43 +0000188#endif
Steve French630f3f0c2007-10-25 21:17:17 +0000189 return;
190}
191
Steve Frenchce06c9f2007-11-08 21:12:01 +0000192/*
193 Generate access flags to reflect permissions mode is the existing mode.
194 This function is called for every ACE in the DACL whose SID matches
195 with either owner or group or everyone.
196*/
197
198static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
199 __u32 *pace_flags)
200{
201 /* reset access mask */
202 *pace_flags = 0x0;
203
204 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
205 mode &= bits_to_use;
206
207 /* check for R/W/X UGO since we do not know whose flags
208 is this but we have cleared all the bits sans RWX for
209 either user or group or other as per bits_to_use */
210 if (mode & S_IRUGO)
211 *pace_flags |= SET_FILE_READ_RIGHTS;
212 if (mode & S_IWUGO)
213 *pace_flags |= SET_FILE_WRITE_RIGHTS;
214 if (mode & S_IXUGO)
215 *pace_flags |= SET_FILE_EXEC_RIGHTS;
216
217#ifdef CONFIG_CIFS_DEBUG2
218 cFYI(1, ("mode: 0x%x, access flags now 0x%x", mode, *pace_flags));
219#endif
220 return;
221}
222
Steve French297647c2007-10-12 04:11:59 +0000223
Steve French953f8682007-10-31 04:54:42 +0000224#ifdef CONFIG_CIFS_DEBUG2
225static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000226{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000227 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000228
229 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000230
Steve French44093ca2007-10-23 21:22:55 +0000231 if (le16_to_cpu(pace->size) < 16) {
232 cERROR(1, ("ACE too small, %d", le16_to_cpu(pace->size)));
233 return;
234 }
235
236 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000237 cERROR(1, ("ACL too small to parse ACE"));
238 return;
Steve French44093ca2007-10-23 21:22:55 +0000239 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000240
Steve French44093ca2007-10-23 21:22:55 +0000241 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000242 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000243 int i;
Steve French44093ca2007-10-23 21:22:55 +0000244 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
245 pace->sid.revision, pace->sid.num_subauth, pace->type,
246 pace->flags, pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000247 for (i = 0; i < num_subauth; ++i) {
248 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
Steve French44093ca2007-10-23 21:22:55 +0000249 le32_to_cpu(pace->sid.sub_auth[i])));
Steve Frenchd12fd122007-10-03 19:43:19 +0000250 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000251
Steve Frenchd12fd122007-10-03 19:43:19 +0000252 /* BB add length check to make sure that we do not have huge
253 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000254 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000255
Steve Frenchd12fd122007-10-03 19:43:19 +0000256 return;
257}
Steve French953f8682007-10-31 04:54:42 +0000258#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000259
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000260
Steve Frencha750e772007-10-17 22:50:39 +0000261static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000262 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Steve French630f3f0c2007-10-25 21:17:17 +0000263 struct inode *inode)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000264{
265 int i;
266 int num_aces = 0;
267 int acl_size;
268 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000269 struct cifs_ace **ppace;
270
271 /* BB need to add parm so we can store the SID BB */
272
Steve French2b834572007-11-25 10:01:00 +0000273 if (!pdacl) {
274 /* no DACL in the security descriptor, set
275 all the permissions for user/group/other */
276 inode->i_mode |= S_IRWXUGO;
277 return;
278 }
279
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000280 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000281 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000282 cERROR(1, ("ACL too small to parse DACL"));
283 return;
284 }
285
286#ifdef CONFIG_CIFS_DEBUG2
287 cFYI(1, ("DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000288 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
289 le32_to_cpu(pdacl->num_aces)));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000290#endif
291
Steve French7505e052007-11-01 18:03:01 +0000292 /* reset rwx permissions for user/group/other.
293 Also, if num_aces is 0 i.e. DACL has no ACEs,
294 user/group/other have no permissions */
295 inode->i_mode &= ~(S_IRWXUGO);
296
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000297 acl_base = (char *)pdacl;
298 acl_size = sizeof(struct cifs_acl);
299
Steve Frenchadbc0352007-10-17 02:12:46 +0000300 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000301 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000302 umode_t user_mask = S_IRWXU;
303 umode_t group_mask = S_IRWXG;
304 umode_t other_mask = S_IRWXO;
305
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000306 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
307 GFP_KERNEL);
308
Steve Frenchd12fd122007-10-03 19:43:19 +0000309/* cifscred->cecount = pdacl->num_aces;
Steve Frenchd12fd122007-10-03 19:43:19 +0000310 cifscred->aces = kmalloc(num_aces *
311 sizeof(struct cifs_ace *), GFP_KERNEL);*/
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000312
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000313 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000314 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000315#ifdef CONFIG_CIFS_DEBUG2
316 dump_ace(ppace[i], end_of_acl);
317#endif
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000318 if (compare_sids(&(ppace[i]->sid), pownersid))
319 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000320 ppace[i]->type,
321 &(inode->i_mode),
322 &user_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000323 if (compare_sids(&(ppace[i]->sid), pgrpsid))
324 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000325 ppace[i]->type,
326 &(inode->i_mode),
327 &group_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000328 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
329 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000330 ppace[i]->type,
331 &(inode->i_mode),
332 &other_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000333
Steve French44093ca2007-10-23 21:22:55 +0000334/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000335 (void *)ppace[i],
336 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000337
Steve French44093ca2007-10-23 21:22:55 +0000338 acl_base = (char *)ppace[i];
339 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000340 }
341
342 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000343 }
344
345 return;
346}
347
Steve Frenchbcb02032007-09-25 16:17:24 +0000348
349static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
350{
351 /* BB need to add parm so we can store the SID BB */
352
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000353 /* validate that we do not go past end of ACL - sid must be at least 8
354 bytes long (assuming no sub-auths - e.g. the null SID */
355 if (end_of_acl < (char *)psid + 8) {
356 cERROR(1, ("ACL too small to parse SID %p", psid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000357 return -EINVAL;
358 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000359
Steve Frenchaf6f4612007-10-16 18:40:37 +0000360 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000361#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000362 int i;
Steve French44093ca2007-10-23 21:22:55 +0000363 cFYI(1, ("SID revision %d num_auth %d",
364 psid->revision, psid->num_subauth));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000365
Steve Frenchaf6f4612007-10-16 18:40:37 +0000366 for (i = 0; i < psid->num_subauth; i++) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000367 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
Steve French297647c2007-10-12 04:11:59 +0000368 le32_to_cpu(psid->sub_auth[i])));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000369 }
370
Steve Frenchd12fd122007-10-03 19:43:19 +0000371 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000372 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000373 cFYI(1, ("RID 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000374 le32_to_cpu(psid->sub_auth[psid->num_subauth-1])));
Steve Frenchbcb02032007-09-25 16:17:24 +0000375#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000376 }
377
Steve Frenchbcb02032007-09-25 16:17:24 +0000378 return 0;
379}
380
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000381
Steve Frenchbcb02032007-09-25 16:17:24 +0000382/* Convert CIFS ACL to POSIX form */
Steve French630f3f0c2007-10-25 21:17:17 +0000383static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
384 struct inode *inode)
Steve Frenchbcb02032007-09-25 16:17:24 +0000385{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000386 int rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000387 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
388 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000389 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000390 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000391
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000392 if ((inode == NULL) || (pntsd == NULL))
393 return -EIO;
394
Steve Frenchbcb02032007-09-25 16:17:24 +0000395 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000396 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000397 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000398 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000399 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000400 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Steve Frenchbcb02032007-09-25 16:17:24 +0000401#ifdef CONFIG_CIFS_DEBUG2
402 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
403 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000404 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
405 le32_to_cpu(pntsd->gsidoffset),
Steve French7505e052007-11-01 18:03:01 +0000406 le32_to_cpu(pntsd->sacloffset), dacloffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000407#endif
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000408/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000409 rc = parse_sid(owner_sid_ptr, end_of_acl);
410 if (rc)
411 return rc;
412
413 rc = parse_sid(group_sid_ptr, end_of_acl);
414 if (rc)
415 return rc;
416
Steve French7505e052007-11-01 18:03:01 +0000417 if (dacloffset)
418 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Steve French63d25832007-11-05 21:46:10 +0000419 group_sid_ptr, inode);
Steve French7505e052007-11-01 18:03:01 +0000420 else
421 cFYI(1, ("no ACL")); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000422
Steve Frenchbcb02032007-09-25 16:17:24 +0000423/* cifscred->uid = owner_sid_ptr->rid;
424 cifscred->gid = group_sid_ptr->rid;
425 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000426 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000427 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000428 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000429
Steve French297647c2007-10-12 04:11:59 +0000430
Steve Frenchbcb02032007-09-25 16:17:24 +0000431 return (0);
432}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000433
434
Steve French7505e052007-11-01 18:03:01 +0000435/* Retrieve an ACL from the server */
436static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
437 const char *path)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000438{
439 struct cifsFileInfo *open_file;
440 int unlock_file = FALSE;
441 int xid;
442 int rc = -EIO;
443 __u16 fid;
444 struct super_block *sb;
445 struct cifs_sb_info *cifs_sb;
446 struct cifs_ntsd *pntsd = NULL;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000447
448 cFYI(1, ("get mode from ACL for %s", path));
449
450 if (inode == NULL)
Steve French7505e052007-11-01 18:03:01 +0000451 return NULL;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000452
453 xid = GetXid();
454 open_file = find_readable_file(CIFS_I(inode));
455 sb = inode->i_sb;
456 if (sb == NULL) {
457 FreeXid(xid);
Steve French7505e052007-11-01 18:03:01 +0000458 return NULL;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000459 }
460 cifs_sb = CIFS_SB(sb);
461
462 if (open_file) {
463 unlock_file = TRUE;
464 fid = open_file->netfid;
465 } else {
466 int oplock = FALSE;
467 /* open file */
468 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
Steve French953f8682007-10-31 04:54:42 +0000469 READ_CONTROL, 0, &fid, &oplock, NULL,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000470 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
471 CIFS_MOUNT_MAP_SPECIAL_CHR);
472 if (rc != 0) {
473 cERROR(1, ("Unable to open file to get ACL"));
474 FreeXid(xid);
Steve French7505e052007-11-01 18:03:01 +0000475 return NULL;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000476 }
477 }
478
Steve French7505e052007-11-01 18:03:01 +0000479 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
480 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000481 if (unlock_file == TRUE)
482 atomic_dec(&open_file->wrtPending);
483 else
484 CIFSSMBClose(xid, cifs_sb->tcon, fid);
485
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000486 FreeXid(xid);
Steve French7505e052007-11-01 18:03:01 +0000487 return pntsd;
488}
489
490/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
491void acl_to_uid_mode(struct inode *inode, const char *path)
492{
493 struct cifs_ntsd *pntsd = NULL;
494 u32 acllen = 0;
495 int rc = 0;
496
497#ifdef CONFIG_CIFS_DEBUG2
498 cFYI(1, ("converting ACL to mode for %s", path));
499#endif
500 pntsd = get_cifs_acl(&acllen, inode, path);
501
502 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
503 if (pntsd)
504 rc = parse_sec_desc(pntsd, acllen, inode);
505 if (rc)
506 cFYI(1, ("parse sec desc failed rc = %d", rc));
507
508 kfree(pntsd);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000509 return;
510}
Steve French953f8682007-10-31 04:54:42 +0000511
Steve French7505e052007-11-01 18:03:01 +0000512/* Convert mode bits to an ACL so we can update the ACL on the server */
Steve French953f8682007-10-31 04:54:42 +0000513int mode_to_acl(struct inode *inode, const char *path)
514{
515 int rc = 0;
516 __u32 acllen = 0;
517 struct cifs_ntsd *pntsd = NULL;
518
519 cFYI(1, ("set ACL from mode for %s", path));
520
521 /* Get the security descriptor */
Steve French7505e052007-11-01 18:03:01 +0000522 pntsd = get_cifs_acl(&acllen, inode, path);
Steve French953f8682007-10-31 04:54:42 +0000523
Steve French7505e052007-11-01 18:03:01 +0000524 /* Add/Modify the three ACEs for owner, group, everyone
525 while retaining the other ACEs */
Steve French953f8682007-10-31 04:54:42 +0000526
527 /* Set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +0000528
Steve French7505e052007-11-01 18:03:01 +0000529
530 kfree(pntsd);
Steve French953f8682007-10-31 04:54:42 +0000531 return rc;
532}
Steve French297647c2007-10-12 04:11:59 +0000533#endif /* CONFIG_CIFS_EXPERIMENTAL */