4 * Copyright (C) International Business Machines Corp., 2007
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * Contains the routines for mapping CIFS/NTFS ACLs
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.
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.
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
28 #include "cifsproto.h"
29 #include "cifs_debug.h"
32 #ifdef CONFIG_CIFS_EXPERIMENTAL
34 static struct cifs_wksid wksidarr
[NUM_WK_SIDS
] = {
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"},
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"},
41 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }
45 /* security id for everyone */
46 static const struct cifs_sid sid_everyone
= {
47 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
49 static const struct cifs_sid sid_user
=
50 {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
53 int match_sid(struct cifs_sid
*ctsid
)
56 int num_subauth
, num_sat
, num_saw
;
57 struct cifs_sid
*cwsid
;
62 for (i
= 0; i
< NUM_WK_SIDS
; ++i
) {
63 cwsid
= &(wksidarr
[i
].cifssid
);
65 /* compare the revision */
66 if (ctsid
->revision
!= cwsid
->revision
)
69 /* compare all of the six auth values */
70 for (j
= 0; j
< 6; ++j
) {
71 if (ctsid
->authority
[j
] != cwsid
->authority
[j
])
75 continue; /* all of the auth values did not match */
77 /* compare all of the subauth values if any */
78 num_sat
= ctsid
->num_subauth
;
79 num_saw
= cwsid
->num_subauth
;
80 num_subauth
= num_sat
< num_saw
? num_sat
: num_saw
;
82 for (j
= 0; j
< num_subauth
; ++j
) {
83 if (ctsid
->sub_auth
[j
] != cwsid
->sub_auth
[j
])
87 continue; /* all sub_auth values do not match */
90 cFYI(1, ("matching sid: %s\n", wksidarr
[i
].sidname
));
91 return (0); /* sids compare/match */
94 cFYI(1, ("No matching sid"));
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 */
100 int compare_sids(const struct cifs_sid
*ctsid
, const struct cifs_sid
*cwsid
)
103 int num_subauth
, num_sat
, num_saw
;
105 if ((!ctsid
) || (!cwsid
))
108 /* compare the revision */
109 if (ctsid
->revision
!= cwsid
->revision
)
112 /* compare all of the six auth values */
113 for (i
= 0; i
< 6; ++i
) {
114 if (ctsid
->authority
[i
] != cwsid
->authority
[i
])
118 /* compare all of the subauth values if any */
119 num_sat
= ctsid
->num_subauth
;
120 num_saw
= cwsid
->num_subauth
;
121 num_subauth
= num_sat
< num_saw
? num_sat
: num_saw
;
123 for (i
= 0; i
< num_subauth
; ++i
) {
124 if (ctsid
->sub_auth
[i
] != cwsid
->sub_auth
[i
])
129 return (1); /* sids compare/match */
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
137 static void access_flags_to_mode(__u32 ace_flags
, umode_t
*pmode
,
141 if (ace_flags
& GENERIC_ALL
) {
142 *pmode
|= (S_IRWXUGO
& bits_to_set
);
143 #ifdef CONFIG_CIFS_DEBUG2
144 cFYI(1, ("all perms"));
148 if ((ace_flags
& GENERIC_WRITE
) ||
149 ((ace_flags
& FILE_WRITE_RIGHTS
) == FILE_WRITE_RIGHTS
))
150 *pmode
|= (S_IWUGO
& bits_to_set
);
151 if ((ace_flags
& GENERIC_READ
) ||
152 ((ace_flags
& FILE_READ_RIGHTS
) == FILE_READ_RIGHTS
))
153 *pmode
|= (S_IRUGO
& bits_to_set
);
154 if ((ace_flags
& GENERIC_EXECUTE
) ||
155 ((ace_flags
& FILE_EXEC_RIGHTS
) == FILE_EXEC_RIGHTS
))
156 *pmode
|= (S_IXUGO
& bits_to_set
);
158 #ifdef CONFIG_CIFS_DEBUG2
159 cFYI(1, ("access flags 0x%x mode now 0x%x", ace_flags
, *pmode
));
165 #ifdef CONFIG_CIFS_DEBUG2
166 static void dump_ace(struct cifs_ace
*pace
, char *end_of_acl
)
170 /* validate that we do not go past end of acl */
172 if (le16_to_cpu(pace
->size
) < 16) {
173 cERROR(1, ("ACE too small, %d", le16_to_cpu(pace
->size
)));
177 if (end_of_acl
< (char *)pace
+ le16_to_cpu(pace
->size
)) {
178 cERROR(1, ("ACL too small to parse ACE"));
182 num_subauth
= pace
->sid
.num_subauth
;
185 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
186 pace
->sid
.revision
, pace
->sid
.num_subauth
, pace
->type
,
187 pace
->flags
, pace
->size
));
188 for (i
= 0; i
< num_subauth
; ++i
) {
189 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i
,
190 le32_to_cpu(pace
->sid
.sub_auth
[i
])));
193 /* BB add length check to make sure that we do not have huge
194 num auths and therefore go off the end */
202 static void parse_dacl(struct cifs_acl
*pdacl
, char *end_of_acl
,
203 struct cifs_sid
*pownersid
, struct cifs_sid
*pgrpsid
,
210 struct cifs_ace
**ppace
;
212 /* BB need to add parm so we can store the SID BB */
214 /* validate that we do not go past end of acl */
215 if (end_of_acl
< (char *)pdacl
+ le16_to_cpu(pdacl
->size
)) {
216 cERROR(1, ("ACL too small to parse DACL"));
220 #ifdef CONFIG_CIFS_DEBUG2
221 cFYI(1, ("DACL revision %d size %d num aces %d",
222 le16_to_cpu(pdacl
->revision
), le16_to_cpu(pdacl
->size
),
223 le32_to_cpu(pdacl
->num_aces
)));
226 acl_base
= (char *)pdacl
;
227 acl_size
= sizeof(struct cifs_acl
);
229 num_aces
= le32_to_cpu(pdacl
->num_aces
);
231 ppace
= kmalloc(num_aces
* sizeof(struct cifs_ace
*),
234 /* cifscred->cecount = pdacl->num_aces;
235 cifscred->aces = kmalloc(num_aces *
236 sizeof(struct cifs_ace *), GFP_KERNEL);*/
238 /* reset rwx permissions for user/group/other */
239 inode
->i_mode
&= ~(S_IRWXUGO
);
241 for (i
= 0; i
< num_aces
; ++i
) {
242 ppace
[i
] = (struct cifs_ace
*) (acl_base
+ acl_size
);
243 #ifdef CONFIG_CIFS_DEBUG2
244 dump_ace(ppace
[i
], end_of_acl
);
246 if (compare_sids(&(ppace
[i
]->sid
), pownersid
))
247 access_flags_to_mode(ppace
[i
]->access_req
,
248 &(inode
->i_mode
), S_IRWXU
);
249 if (compare_sids(&(ppace
[i
]->sid
), pgrpsid
))
250 access_flags_to_mode(ppace
[i
]->access_req
,
251 &(inode
->i_mode
), S_IRWXG
);
252 if (compare_sids(&(ppace
[i
]->sid
), &sid_everyone
))
253 access_flags_to_mode(ppace
[i
]->access_req
,
254 &(inode
->i_mode
), S_IRWXO
);
256 /* memcpy((void *)(&(cifscred->aces[i])),
258 sizeof(struct cifs_ace)); */
260 acl_base
= (char *)ppace
[i
];
261 acl_size
= le16_to_cpu(ppace
[i
]->size
);
271 static int parse_sid(struct cifs_sid
*psid
, char *end_of_acl
)
273 /* BB need to add parm so we can store the SID BB */
275 /* validate that we do not go past end of ACL - sid must be at least 8
276 bytes long (assuming no sub-auths - e.g. the null SID */
277 if (end_of_acl
< (char *)psid
+ 8) {
278 cERROR(1, ("ACL too small to parse SID %p", psid
));
282 if (psid
->num_subauth
) {
283 #ifdef CONFIG_CIFS_DEBUG2
285 cFYI(1, ("SID revision %d num_auth %d",
286 psid
->revision
, psid
->num_subauth
));
288 for (i
= 0; i
< psid
->num_subauth
; i
++) {
289 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i
,
290 le32_to_cpu(psid
->sub_auth
[i
])));
293 /* BB add length check to make sure that we do not have huge
294 num auths and therefore go off the end */
296 le32_to_cpu(psid
->sub_auth
[psid
->num_subauth
-1])));
304 /* Convert CIFS ACL to POSIX form */
305 static int parse_sec_desc(struct cifs_ntsd
*pntsd
, int acl_len
,
309 struct cifs_sid
*owner_sid_ptr
, *group_sid_ptr
;
310 struct cifs_acl
*dacl_ptr
; /* no need for SACL ptr */
311 char *end_of_acl
= ((char *)pntsd
) + acl_len
;
313 if ((inode
== NULL
) || (pntsd
== NULL
))
316 owner_sid_ptr
= (struct cifs_sid
*)((char *)pntsd
+
317 le32_to_cpu(pntsd
->osidoffset
));
318 group_sid_ptr
= (struct cifs_sid
*)((char *)pntsd
+
319 le32_to_cpu(pntsd
->gsidoffset
));
320 dacl_ptr
= (struct cifs_acl
*)((char *)pntsd
+
321 le32_to_cpu(pntsd
->dacloffset
));
322 #ifdef CONFIG_CIFS_DEBUG2
323 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
324 "sacloffset 0x%x dacloffset 0x%x",
325 pntsd
->revision
, pntsd
->type
, le32_to_cpu(pntsd
->osidoffset
),
326 le32_to_cpu(pntsd
->gsidoffset
),
327 le32_to_cpu(pntsd
->sacloffset
),
328 le32_to_cpu(pntsd
->dacloffset
)));
330 /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
331 rc
= parse_sid(owner_sid_ptr
, end_of_acl
);
335 rc
= parse_sid(group_sid_ptr
, end_of_acl
);
339 parse_dacl(dacl_ptr
, end_of_acl
, owner_sid_ptr
, group_sid_ptr
, inode
);
341 /* cifscred->uid = owner_sid_ptr->rid;
342 cifscred->gid = group_sid_ptr->rid;
343 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
344 sizeof(struct cifs_sid));
345 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
346 sizeof(struct cifs_sid)); */
353 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
355 void acl_to_uid_mode(struct inode
*inode
, const char *path
)
357 struct cifsFileInfo
*open_file
;
358 int unlock_file
= FALSE
;
362 struct super_block
*sb
;
363 struct cifs_sb_info
*cifs_sb
;
364 struct cifs_ntsd
*pntsd
= NULL
;
367 cFYI(1, ("get mode from ACL for %s", path
));
373 open_file
= find_readable_file(CIFS_I(inode
));
379 cifs_sb
= CIFS_SB(sb
);
383 fid
= open_file
->netfid
;
387 rc
= CIFSSMBOpen(xid
, cifs_sb
->tcon
, path
, FILE_OPEN
,
388 READ_CONTROL
, 0, &fid
, &oplock
, NULL
,
389 cifs_sb
->local_nls
, cifs_sb
->mnt_cifs_flags
&
390 CIFS_MOUNT_MAP_SPECIAL_CHR
);
392 cERROR(1, ("Unable to open file to get ACL"));
398 rc
= CIFSSMBGetCIFSACL(xid
, cifs_sb
->tcon
, fid
, &pntsd
, &acllen
);
399 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc
, acllen
));
400 if (unlock_file
== TRUE
)
401 atomic_dec(&open_file
->wrtPending
);
403 CIFSSMBClose(xid
, cifs_sb
->tcon
, fid
);
407 rc
= parse_sec_desc(pntsd
, acllen
, inode
);
413 int mode_to_acl(struct inode
*inode
, const char *path
)
417 struct cifs_ntsd
*pntsd
= NULL
;
419 cFYI(1, ("set ACL from mode for %s", path
));
421 /* Get the security descriptor */
423 /* Add/Modify the three ACEs for owner, group, everyone */
425 /* Set the security descriptor */
430 #endif /* CONFIG_CIFS_EXPERIMENTAL */