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 /* reset rwx permissions for user/group/other.
227 Also, if num_aces is 0 i.e. DACL has no ACEs,
228 user/group/other have no permissions */
229 inode
->i_mode
&= ~(S_IRWXUGO
);
232 /* no DACL in the security descriptor, set
233 all the permissions for user/group/other */
234 inode
->i_mode
|= S_IRWXUGO
;
237 acl_base
= (char *)pdacl
;
238 acl_size
= sizeof(struct cifs_acl
);
240 num_aces
= le32_to_cpu(pdacl
->num_aces
);
242 ppace
= kmalloc(num_aces
* sizeof(struct cifs_ace
*),
245 /* cifscred->cecount = pdacl->num_aces;
246 cifscred->aces = kmalloc(num_aces *
247 sizeof(struct cifs_ace *), GFP_KERNEL);*/
249 for (i
= 0; i
< num_aces
; ++i
) {
250 ppace
[i
] = (struct cifs_ace
*) (acl_base
+ acl_size
);
251 #ifdef CONFIG_CIFS_DEBUG2
252 dump_ace(ppace
[i
], end_of_acl
);
254 if (compare_sids(&(ppace
[i
]->sid
), pownersid
))
255 access_flags_to_mode(ppace
[i
]->access_req
,
256 &(inode
->i_mode
), S_IRWXU
);
257 if (compare_sids(&(ppace
[i
]->sid
), pgrpsid
))
258 access_flags_to_mode(ppace
[i
]->access_req
,
259 &(inode
->i_mode
), S_IRWXG
);
260 if (compare_sids(&(ppace
[i
]->sid
), &sid_everyone
))
261 access_flags_to_mode(ppace
[i
]->access_req
,
262 &(inode
->i_mode
), S_IRWXO
);
264 /* memcpy((void *)(&(cifscred->aces[i])),
266 sizeof(struct cifs_ace)); */
268 acl_base
= (char *)ppace
[i
];
269 acl_size
= le16_to_cpu(ppace
[i
]->size
);
279 static int parse_sid(struct cifs_sid
*psid
, char *end_of_acl
)
281 /* BB need to add parm so we can store the SID BB */
283 /* validate that we do not go past end of ACL - sid must be at least 8
284 bytes long (assuming no sub-auths - e.g. the null SID */
285 if (end_of_acl
< (char *)psid
+ 8) {
286 cERROR(1, ("ACL too small to parse SID %p", psid
));
290 if (psid
->num_subauth
) {
291 #ifdef CONFIG_CIFS_DEBUG2
293 cFYI(1, ("SID revision %d num_auth %d",
294 psid
->revision
, psid
->num_subauth
));
296 for (i
= 0; i
< psid
->num_subauth
; i
++) {
297 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i
,
298 le32_to_cpu(psid
->sub_auth
[i
])));
301 /* BB add length check to make sure that we do not have huge
302 num auths and therefore go off the end */
304 le32_to_cpu(psid
->sub_auth
[psid
->num_subauth
-1])));
312 /* Convert CIFS ACL to POSIX form */
313 static int parse_sec_desc(struct cifs_ntsd
*pntsd
, int acl_len
,
317 struct cifs_sid
*owner_sid_ptr
, *group_sid_ptr
;
318 struct cifs_acl
*dacl_ptr
; /* no need for SACL ptr */
319 char *end_of_acl
= ((char *)pntsd
) + acl_len
;
322 if ((inode
== NULL
) || (pntsd
== NULL
))
325 owner_sid_ptr
= (struct cifs_sid
*)((char *)pntsd
+
326 le32_to_cpu(pntsd
->osidoffset
));
327 group_sid_ptr
= (struct cifs_sid
*)((char *)pntsd
+
328 le32_to_cpu(pntsd
->gsidoffset
));
329 dacloffset
= le32_to_cpu(pntsd
->dacloffset
);
330 dacl_ptr
= (struct cifs_acl
*)((char *)pntsd
+ dacloffset
);
331 #ifdef CONFIG_CIFS_DEBUG2
332 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
333 "sacloffset 0x%x dacloffset 0x%x",
334 pntsd
->revision
, pntsd
->type
, le32_to_cpu(pntsd
->osidoffset
),
335 le32_to_cpu(pntsd
->gsidoffset
),
336 le32_to_cpu(pntsd
->sacloffset
), dacloffset
));
338 /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
339 rc
= parse_sid(owner_sid_ptr
, end_of_acl
);
343 rc
= parse_sid(group_sid_ptr
, end_of_acl
);
348 parse_dacl(dacl_ptr
, end_of_acl
, owner_sid_ptr
,
349 group_sid_ptr
, inode
);
351 cFYI(1, ("no ACL")); /* BB grant all or default perms? */
353 /* cifscred->uid = owner_sid_ptr->rid;
354 cifscred->gid = group_sid_ptr->rid;
355 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
356 sizeof(struct cifs_sid));
357 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
358 sizeof(struct cifs_sid)); */
365 /* Retrieve an ACL from the server */
366 static struct cifs_ntsd
*get_cifs_acl(u32
*pacllen
, struct inode
*inode
,
369 struct cifsFileInfo
*open_file
;
370 int unlock_file
= FALSE
;
374 struct super_block
*sb
;
375 struct cifs_sb_info
*cifs_sb
;
376 struct cifs_ntsd
*pntsd
= NULL
;
378 cFYI(1, ("get mode from ACL for %s", path
));
384 open_file
= find_readable_file(CIFS_I(inode
));
390 cifs_sb
= CIFS_SB(sb
);
394 fid
= open_file
->netfid
;
398 rc
= CIFSSMBOpen(xid
, cifs_sb
->tcon
, path
, FILE_OPEN
,
399 READ_CONTROL
, 0, &fid
, &oplock
, NULL
,
400 cifs_sb
->local_nls
, cifs_sb
->mnt_cifs_flags
&
401 CIFS_MOUNT_MAP_SPECIAL_CHR
);
403 cERROR(1, ("Unable to open file to get ACL"));
409 rc
= CIFSSMBGetCIFSACL(xid
, cifs_sb
->tcon
, fid
, &pntsd
, pacllen
);
410 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc
, *pacllen
));
411 if (unlock_file
== TRUE
)
412 atomic_dec(&open_file
->wrtPending
);
414 CIFSSMBClose(xid
, cifs_sb
->tcon
, fid
);
420 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
421 void acl_to_uid_mode(struct inode
*inode
, const char *path
)
423 struct cifs_ntsd
*pntsd
= NULL
;
427 #ifdef CONFIG_CIFS_DEBUG2
428 cFYI(1, ("converting ACL to mode for %s", path
));
430 pntsd
= get_cifs_acl(&acllen
, inode
, path
);
432 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
434 rc
= parse_sec_desc(pntsd
, acllen
, inode
);
436 cFYI(1, ("parse sec desc failed rc = %d", rc
));
442 /* Convert mode bits to an ACL so we can update the ACL on the server */
443 int mode_to_acl(struct inode
*inode
, const char *path
)
447 struct cifs_ntsd
*pntsd
= NULL
;
449 cFYI(1, ("set ACL from mode for %s", path
));
451 /* Get the security descriptor */
452 pntsd
= get_cifs_acl(&acllen
, inode
, path
);
454 /* Add/Modify the three ACEs for owner, group, everyone
455 while retaining the other ACEs */
457 /* Set the security descriptor */
463 #endif /* CONFIG_CIFS_EXPERIMENTAL */