[CIFS] fix unicode string alignment in SPNEGO setup
[deliverable/linux.git] / fs / cifs / cifsacl.c
CommitLineData
bcb02034
SF
1/*
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
65874007
SF
24#include <linux/fs.h>
25#include "cifspdu.h"
26#include "cifsglob.h"
d0d66c44 27#include "cifsacl.h"
65874007
SF
28#include "cifsproto.h"
29#include "cifs_debug.h"
65874007 30
297647c2
SF
31
32#ifdef CONFIG_CIFS_EXPERIMENTAL
33
af6f4612 34static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
297647c2
SF
35 {{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"},
ce51ae14
DK
37 {{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"},
44093ca2
SF
41 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }
42;
297647c2
SF
43
44
bcb02034 45/* security id for everyone */
e01b6400
SP
46static const struct cifs_sid sid_everyone = {
47 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
bcb02034
SF
48/* group users */
49static const struct cifs_sid sid_user =
d12fd121 50 {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 51
297647c2
SF
52
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 */
ce51ae14
DK
78 num_sat = ctsid->num_subauth;
79 num_saw = cwsid->num_subauth;
297647c2
SF
80 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
a750e77c
SF
98/* 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 */
630f3f0c 100int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
297647c2
SF
101{
102 int i;
103 int num_subauth, num_sat, num_saw;
104
105 if ((!ctsid) || (!cwsid))
a750e77c 106 return (0);
297647c2
SF
107
108 /* compare the revision */
109 if (ctsid->revision != cwsid->revision)
a750e77c 110 return (0);
297647c2
SF
111
112 /* compare all of the six auth values */
113 for (i = 0; i < 6; ++i) {
114 if (ctsid->authority[i] != cwsid->authority[i])
a750e77c 115 return (0);
297647c2
SF
116 }
117
118 /* compare all of the subauth values if any */
adbc0358 119 num_sat = ctsid->num_subauth;
adddd49d 120 num_saw = cwsid->num_subauth;
297647c2
SF
121 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])
a750e77c 125 return (0);
297647c2
SF
126 }
127 }
128
a750e77c 129 return (1); /* sids compare/match */
297647c2
SF
130}
131
630f3f0c
SF
132/*
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*/
9b5e6857 137static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
15b03959 138 umode_t *pbits_to_set)
630f3f0c 139{
9b5e6857 140 __u32 flags = le32_to_cpu(ace_flags);
15b03959 141 /* the order of ACEs is important. The canonical order is to begin with
ce06c9f0 142 DENY entries followed by ALLOW, otherwise an allow entry could be
15b03959 143 encountered first, making the subsequent deny entry like "dead code"
ce06c9f0 144 which would be superflous since Windows stops when a match is made
15b03959
SF
145 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) {
9b5e6857 150 if (flags & GENERIC_ALL) {
15b03959
SF
151 *pbits_to_set &= ~S_IRWXUGO;
152 }
9b5e6857
AV
153 if ((flags & GENERIC_WRITE) ||
154 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 155 *pbits_to_set &= ~S_IWUGO;
9b5e6857
AV
156 if ((flags & GENERIC_READ) ||
157 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 158 *pbits_to_set &= ~S_IRUGO;
9b5e6857
AV
159 if ((flags & GENERIC_EXECUTE) ||
160 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959
SF
161 *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 */
630f3f0c 168
9b5e6857 169 if (flags & GENERIC_ALL) {
15b03959 170 *pmode |= (S_IRWXUGO & (*pbits_to_set));
630f3f0c 171#ifdef CONFIG_CIFS_DEBUG2
d61e5808 172 cFYI(1, ("all perms"));
630f3f0c 173#endif
d61e5808
SF
174 return;
175 }
9b5e6857
AV
176 if ((flags & GENERIC_WRITE) ||
177 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 178 *pmode |= (S_IWUGO & (*pbits_to_set));
9b5e6857
AV
179 if ((flags & GENERIC_READ) ||
180 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 181 *pmode |= (S_IRUGO & (*pbits_to_set));
9b5e6857
AV
182 if ((flags & GENERIC_EXECUTE) ||
183 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 184 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 185
d61e5808 186#ifdef CONFIG_CIFS_DEBUG2
9b5e6857 187 cFYI(1, ("access flags 0x%x mode now 0x%x", flags, *pmode));
d61e5808 188#endif
630f3f0c
SF
189 return;
190}
191
ce06c9f0
SF
192/*
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
297647c2 223
953f8681
SF
224#ifdef CONFIG_CIFS_DEBUG2
225static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 226{
d0d66c44 227 int num_subauth;
d0d66c44
SP
228
229 /* validate that we do not go past end of acl */
297647c2 230
44093ca2
SF
231 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)) {
d0d66c44
SP
237 cERROR(1, ("ACL too small to parse ACE"));
238 return;
44093ca2 239 }
d0d66c44 240
44093ca2 241 num_subauth = pace->sid.num_subauth;
d0d66c44 242 if (num_subauth) {
8f18c131 243 int i;
44093ca2
SF
244 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));
d12fd121
SF
247 for (i = 0; i < num_subauth; ++i) {
248 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
44093ca2 249 le32_to_cpu(pace->sid.sub_auth[i])));
d12fd121
SF
250 }
251
252 /* BB add length check to make sure that we do not have huge
253 num auths and therefore go off the end */
d12fd121
SF
254 }
255
256 return;
257}
953f8681 258#endif
d12fd121 259
d0d66c44 260
a750e77c 261static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 262 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
630f3f0c 263 struct inode *inode)
d0d66c44
SP
264{
265 int i;
266 int num_aces = 0;
267 int acl_size;
268 char *acl_base;
d0d66c44
SP
269 struct cifs_ace **ppace;
270
271 /* BB need to add parm so we can store the SID BB */
272
2b83457b
SF
273 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
d0d66c44 280 /* validate that we do not go past end of acl */
af6f4612 281 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
d0d66c44
SP
282 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",
af6f4612
SF
288 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
289 le32_to_cpu(pdacl->num_aces)));
d0d66c44
SP
290#endif
291
7505e052
SF
292 /* 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
d0d66c44
SP
297 acl_base = (char *)pdacl;
298 acl_size = sizeof(struct cifs_acl);
299
adbc0358 300 num_aces = le32_to_cpu(pdacl->num_aces);
d0d66c44 301 if (num_aces > 0) {
15b03959
SF
302 umode_t user_mask = S_IRWXU;
303 umode_t group_mask = S_IRWXG;
304 umode_t other_mask = S_IRWXO;
305
d0d66c44
SP
306 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
307 GFP_KERNEL);
308
d12fd121 309/* cifscred->cecount = pdacl->num_aces;
d12fd121
SF
310 cifscred->aces = kmalloc(num_aces *
311 sizeof(struct cifs_ace *), GFP_KERNEL);*/
d0d66c44 312
d0d66c44 313 for (i = 0; i < num_aces; ++i) {
44093ca2 314 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
315#ifdef CONFIG_CIFS_DEBUG2
316 dump_ace(ppace[i], end_of_acl);
317#endif
e01b6400
SP
318 if (compare_sids(&(ppace[i]->sid), pownersid))
319 access_flags_to_mode(ppace[i]->access_req,
15b03959
SF
320 ppace[i]->type,
321 &(inode->i_mode),
322 &user_mask);
e01b6400
SP
323 if (compare_sids(&(ppace[i]->sid), pgrpsid))
324 access_flags_to_mode(ppace[i]->access_req,
15b03959
SF
325 ppace[i]->type,
326 &(inode->i_mode),
327 &group_mask);
e01b6400
SP
328 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
329 access_flags_to_mode(ppace[i]->access_req,
15b03959
SF
330 ppace[i]->type,
331 &(inode->i_mode),
332 &other_mask);
e01b6400 333
44093ca2 334/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
335 (void *)ppace[i],
336 sizeof(struct cifs_ace)); */
d0d66c44 337
44093ca2
SF
338 acl_base = (char *)ppace[i];
339 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
340 }
341
342 kfree(ppace);
d0d66c44
SP
343 }
344
345 return;
346}
347
bcb02034
SF
348
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
b9c7a2bb
SF
353 /* 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));
bcb02034
SF
357 return -EINVAL;
358 }
d0d66c44 359
af6f4612 360 if (psid->num_subauth) {
bcb02034 361#ifdef CONFIG_CIFS_DEBUG2
8f18c131 362 int i;
44093ca2
SF
363 cFYI(1, ("SID revision %d num_auth %d",
364 psid->revision, psid->num_subauth));
bcb02034 365
af6f4612 366 for (i = 0; i < psid->num_subauth; i++) {
d0d66c44 367 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
297647c2 368 le32_to_cpu(psid->sub_auth[i])));
d0d66c44
SP
369 }
370
d12fd121 371 /* BB add length check to make sure that we do not have huge
d0d66c44 372 num auths and therefore go off the end */
d12fd121 373 cFYI(1, ("RID 0x%x",
af6f4612 374 le32_to_cpu(psid->sub_auth[psid->num_subauth-1])));
bcb02034 375#endif
d0d66c44
SP
376 }
377
bcb02034
SF
378 return 0;
379}
380
d0d66c44 381
bcb02034 382/* Convert CIFS ACL to POSIX form */
630f3f0c
SF
383static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
384 struct inode *inode)
bcb02034 385{
d0d66c44 386 int rc;
bcb02034
SF
387 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
388 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 389 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 390 __u32 dacloffset;
bcb02034 391
b9c7a2bb
SF
392 if ((inode == NULL) || (pntsd == NULL))
393 return -EIO;
394
bcb02034 395 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 396 le32_to_cpu(pntsd->osidoffset));
bcb02034 397 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 398 le32_to_cpu(pntsd->gsidoffset));
7505e052 399 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 400 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
bcb02034
SF
401#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",
af6f4612
SF
404 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
405 le32_to_cpu(pntsd->gsidoffset),
7505e052 406 le32_to_cpu(pntsd->sacloffset), dacloffset));
bcb02034 407#endif
b9c7a2bb 408/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034
SF
409 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
7505e052
SF
417 if (dacloffset)
418 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
63d2583f 419 group_sid_ptr, inode);
7505e052
SF
420 else
421 cFYI(1, ("no ACL")); /* BB grant all or default perms? */
d0d66c44 422
bcb02034
SF
423/* cifscred->uid = owner_sid_ptr->rid;
424 cifscred->gid = group_sid_ptr->rid;
425 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
630f3f0c 426 sizeof(struct cifs_sid));
bcb02034 427 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
630f3f0c 428 sizeof(struct cifs_sid)); */
bcb02034 429
297647c2 430
bcb02034
SF
431 return (0);
432}
b9c7a2bb
SF
433
434
7505e052
SF
435/* Retrieve an ACL from the server */
436static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
437 const char *path)
b9c7a2bb
SF
438{
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;
b9c7a2bb
SF
447
448 cFYI(1, ("get mode from ACL for %s", path));
449
450 if (inode == NULL)
7505e052 451 return NULL;
b9c7a2bb
SF
452
453 xid = GetXid();
454 open_file = find_readable_file(CIFS_I(inode));
455 sb = inode->i_sb;
456 if (sb == NULL) {
457 FreeXid(xid);
7505e052 458 return NULL;
b9c7a2bb
SF
459 }
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,
953f8681 469 READ_CONTROL, 0, &fid, &oplock, NULL,
b9c7a2bb
SF
470 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);
7505e052 475 return NULL;
b9c7a2bb
SF
476 }
477 }
478
7505e052
SF
479 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
480 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
b9c7a2bb
SF
481 if (unlock_file == TRUE)
482 atomic_dec(&open_file->wrtPending);
483 else
484 CIFSSMBClose(xid, cifs_sb->tcon, fid);
485
7505e052
SF
486 FreeXid(xid);
487 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)
b9c7a2bb 504 rc = parse_sec_desc(pntsd, acllen, inode);
7505e052
SF
505 if (rc)
506 cFYI(1, ("parse sec desc failed rc = %d", rc));
507
b9c7a2bb 508 kfree(pntsd);
b9c7a2bb
SF
509 return;
510}
953f8681 511
7505e052 512/* Convert mode bits to an ACL so we can update the ACL on the server */
953f8681
SF
513int 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 */
7505e052 522 pntsd = get_cifs_acl(&acllen, inode, path);
953f8681 523
7505e052
SF
524 /* Add/Modify the three ACEs for owner, group, everyone
525 while retaining the other ACEs */
953f8681
SF
526
527 /* Set the security descriptor */
953f8681 528
7505e052
SF
529
530 kfree(pntsd);
953f8681
SF
531 return rc;
532}
297647c2 533#endif /* CONFIG_CIFS_EXPERIMENTAL */
This page took 0.062602 seconds and 5 git commands to generate.