2007-09-25 20:17:24 +04:00
/*
* fs / cifs / cifsacl . c
*
* Copyright ( C ) International Business Machines Corp . , 2007
* Author ( s ) : Steve French ( sfrench @ us . ibm . com )
*
* Contains the routines for mapping CIFS / NTFS ACLs
*
* This library is free software ; you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation ; either version 2.1 of the License , or
* ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See
* the GNU Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2007-09-25 23:53:44 +04:00
# include <linux/fs.h>
# include "cifspdu.h"
# include "cifsglob.h"
2007-10-03 22:22:19 +04:00
# include "cifsacl.h"
2007-09-25 23:53:44 +04:00
# include "cifsproto.h"
# include "cifs_debug.h"
2007-10-12 08:11:59 +04:00
# ifdef CONFIG_CIFS_EXPERIMENTAL
2007-10-16 22:40:37 +04:00
static struct cifs_wksid wksidarr [ NUM_WK_SIDS ] = {
2007-10-12 08:11:59 +04:00
{ { 1 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } , { 0 , 0 , 0 , 0 , 0 } } , " null user " } ,
{ { 1 , 1 , { 0 , 0 , 0 , 0 , 0 , 1 } , { 0 , 0 , 0 , 0 , 0 } } , " nobody " } ,
2007-10-17 01:35:39 +04:00
{ { 1 , 1 , { 0 , 0 , 0 , 0 , 0 , 5 } , { cpu_to_le32 ( 11 ) , 0 , 0 , 0 , 0 } } , " net-users " } ,
{ { 1 , 1 , { 0 , 0 , 0 , 0 , 0 , 5 } , { cpu_to_le32 ( 18 ) , 0 , 0 , 0 , 0 } } , " sys " } ,
{ { 1 , 2 , { 0 , 0 , 0 , 0 , 0 , 5 } , { cpu_to_le32 ( 32 ) , cpu_to_le32 ( 544 ) , 0 , 0 , 0 } } , " root " } ,
{ { 1 , 2 , { 0 , 0 , 0 , 0 , 0 , 5 } , { cpu_to_le32 ( 32 ) , cpu_to_le32 ( 545 ) , 0 , 0 , 0 } } , " users " } ,
{ { 1 , 2 , { 0 , 0 , 0 , 0 , 0 , 5 } , { cpu_to_le32 ( 32 ) , cpu_to_le32 ( 546 ) , 0 , 0 , 0 } } , " guest " }
2007-10-12 08:11:59 +04:00
} ;
2007-09-25 20:17:24 +04:00
/* security id for everyone */
static const struct cifs_sid sid_everyone =
2007-10-03 23:43:19 +04:00
{ 1 , 1 , { 0 , 0 , 0 , 0 , 0 , 0 } , { } } ;
2007-09-25 20:17:24 +04:00
/* group users */
static const struct cifs_sid sid_user =
2007-10-03 23:43:19 +04:00
{ 1 , 2 , { 0 , 0 , 0 , 0 , 0 , 5 } , { } } ;
2007-10-03 22:22:19 +04:00
2007-10-12 08:11:59 +04:00
int match_sid ( struct cifs_sid * ctsid )
{
int i , j ;
int num_subauth , num_sat , num_saw ;
struct cifs_sid * cwsid ;
if ( ! ctsid )
return ( - 1 ) ;
for ( i = 0 ; i < NUM_WK_SIDS ; + + i ) {
cwsid = & ( wksidarr [ i ] . cifssid ) ;
/* compare the revision */
if ( ctsid - > revision ! = cwsid - > revision )
continue ;
/* compare all of the six auth values */
for ( j = 0 ; j < 6 ; + + j ) {
if ( ctsid - > authority [ j ] ! = cwsid - > authority [ j ] )
break ;
}
if ( j < 6 )
continue ; /* all of the auth values did not match */
/* compare all of the subauth values if any */
2007-10-17 01:35:39 +04:00
num_sat = ctsid - > num_subauth ;
num_saw = cwsid - > num_subauth ;
2007-10-12 08:11:59 +04:00
num_subauth = num_sat < num_saw ? num_sat : num_saw ;
if ( num_subauth ) {
for ( j = 0 ; j < num_subauth ; + + j ) {
if ( ctsid - > sub_auth [ j ] ! = cwsid - > sub_auth [ j ] )
break ;
}
if ( j < num_subauth )
continue ; /* all sub_auth values do not match */
}
cFYI ( 1 , ( " matching sid: %s \n " , wksidarr [ i ] . sidname ) ) ;
return ( 0 ) ; /* sids compare/match */
}
cFYI ( 1 , ( " No matching sid " ) ) ;
return ( - 1 ) ;
}
int compare_sids ( struct cifs_sid * ctsid , struct cifs_sid * cwsid )
{
int i ;
int num_subauth , num_sat , num_saw ;
if ( ( ! ctsid ) | | ( ! cwsid ) )
return ( - 1 ) ;
/* compare the revision */
if ( ctsid - > revision ! = cwsid - > revision )
return ( - 1 ) ;
/* compare all of the six auth values */
for ( i = 0 ; i < 6 ; + + i ) {
if ( ctsid - > authority [ i ] ! = cwsid - > authority [ i ] )
return ( - 1 ) ;
}
/* compare all of the subauth values if any */
2007-10-17 06:12:46 +04:00
num_sat = ctsid - > num_subauth ;
num_saw = cwsid - > num_subauth ) ;
2007-10-12 08:11:59 +04:00
num_subauth = num_sat < num_saw ? num_sat : num_saw ;
if ( num_subauth ) {
for ( i = 0 ; i < num_subauth ; + + i ) {
if ( ctsid - > sub_auth [ i ] ! = cwsid - > sub_auth [ i ] )
return ( - 1 ) ;
}
}
return ( 0 ) ; /* sids compare/match */
}
2007-10-03 23:43:19 +04:00
static void parse_ace ( struct cifs_ace * pace , char * end_of_acl )
2007-10-03 22:22:19 +04:00
{
int num_subauth ;
/* validate that we do not go past end of acl */
2007-10-12 08:11:59 +04:00
/* XXX this if statement can be removed
2007-10-03 22:22:19 +04:00
if ( end_of_acl < ( char * ) pace + sizeof ( struct cifs_ace ) ) {
cERROR ( 1 , ( " ACL too small to parse ACE " ) ) ;
return ;
2007-10-12 08:11:59 +04:00
} */
2007-10-03 22:22:19 +04:00
2007-10-17 01:35:39 +04:00
num_subauth = pace - > num_subauth ;
2007-10-03 22:22:19 +04:00
if ( num_subauth ) {
2007-10-03 23:43:19 +04:00
# ifdef CONFIG_CIFS_DEBUG2
2007-10-12 22:54:12 +04:00
int i ;
2007-10-03 23:43:19 +04:00
cFYI ( 1 , ( " ACE revision %d num_subauth %d " ,
pace - > revision , pace - > num_subauth ) ) ;
for ( i = 0 ; i < num_subauth ; + + i ) {
cFYI ( 1 , ( " ACE sub_auth[%d]: 0x%x " , i ,
2007-10-12 08:11:59 +04:00
le32_to_cpu ( pace - > sub_auth [ i ] ) ) ) ;
2007-10-03 23:43:19 +04:00
}
/* BB add length check to make sure that we do not have huge
num auths and therefore go off the end */
2007-10-12 08:11:59 +04:00
cFYI ( 1 , ( " RID %d " , le32_to_cpu ( pace - > sub_auth [ num_subauth - 1 ] ) ) ) ;
2007-10-03 23:43:19 +04:00
# endif
}
return ;
}
static void parse_ntace ( struct cifs_ntace * pntace , char * end_of_acl )
{
/* validate that we do not go past end of acl */
2007-10-03 22:22:19 +04:00
if ( end_of_acl < ( char * ) pntace + sizeof ( struct cifs_ntace ) ) {
cERROR ( 1 , ( " ACL too small to parse NT ACE " ) ) ;
return ;
}
# ifdef CONFIG_CIFS_DEBUG2
cFYI ( 1 , ( " NTACE type %d flags 0x%x size %d, access Req 0x%x " ,
pntace - > type , pntace - > flags , pntace - > size ,
pntace - > access_req ) ) ;
# endif
return ;
}
2007-10-03 23:43:19 +04:00
static void parse_dacl ( struct cifs_acl * pdacl , char * end_of_acl )
2007-10-03 22:22:19 +04:00
{
int i ;
int num_aces = 0 ;
int acl_size ;
char * acl_base ;
struct cifs_ntace * * ppntace ;
struct cifs_ace * * ppace ;
/* BB need to add parm so we can store the SID BB */
/* validate that we do not go past end of acl */
2007-10-16 22:40:37 +04:00
if ( end_of_acl < ( char * ) pdacl + le16_to_cpu ( pdacl - > size ) ) {
2007-10-03 22:22:19 +04:00
cERROR ( 1 , ( " ACL too small to parse DACL " ) ) ;
return ;
}
# ifdef CONFIG_CIFS_DEBUG2
cFYI ( 1 , ( " DACL revision %d size %d num aces %d " ,
2007-10-16 22:40:37 +04:00
le16_to_cpu ( pdacl - > revision ) , le16_to_cpu ( pdacl - > size ) ,
le32_to_cpu ( pdacl - > num_aces ) ) ) ;
2007-10-03 22:22:19 +04:00
# endif
acl_base = ( char * ) pdacl ;
acl_size = sizeof ( struct cifs_acl ) ;
2007-10-17 06:12:46 +04:00
num_aces = le32_to_cpu ( pdacl - > num_aces ) ;
2007-10-03 22:22:19 +04:00
if ( num_aces > 0 ) {
ppntace = kmalloc ( num_aces * sizeof ( struct cifs_ntace * ) ,
GFP_KERNEL ) ;
ppace = kmalloc ( num_aces * sizeof ( struct cifs_ace * ) ,
GFP_KERNEL ) ;
2007-10-03 23:43:19 +04:00
/* cifscred->cecount = pdacl->num_aces;
cifscred - > ntaces = kmalloc ( num_aces *
sizeof ( struct cifs_ntace * ) , GFP_KERNEL ) ;
cifscred - > aces = kmalloc ( num_aces *
sizeof ( struct cifs_ace * ) , GFP_KERNEL ) ; */
2007-10-03 22:22:19 +04:00
for ( i = 0 ; i < num_aces ; + + i ) {
ppntace [ i ] = ( struct cifs_ntace * )
( acl_base + acl_size ) ;
ppace [ i ] = ( struct cifs_ace * ) ( ( char * ) ppntace [ i ] +
sizeof ( struct cifs_ntace ) ) ;
parse_ntace ( ppntace [ i ] , end_of_acl ) ;
2007-10-12 08:11:59 +04:00
if ( end_of_acl < ( ( char * ) ppace [ i ] +
2007-10-17 01:35:39 +04:00
( le16_to_cpu ( ppntace [ i ] - > size ) -
2007-10-12 08:11:59 +04:00
sizeof ( struct cifs_ntace ) ) ) ) {
cERROR ( 1 , ( " ACL too small to parse ACE " ) ) ;
break ;
} else
parse_ace ( ppace [ i ] , end_of_acl ) ;
2007-10-03 22:22:19 +04:00
2007-10-03 23:43:19 +04:00
/* memcpy((void *)(&(cifscred->ntaces[i])),
( void * ) ppntace [ i ] ,
sizeof ( struct cifs_ntace ) ) ;
memcpy ( ( void * ) ( & ( cifscred - > aces [ i ] ) ) ,
( void * ) ppace [ i ] ,
sizeof ( struct cifs_ace ) ) ; */
2007-10-03 22:22:19 +04:00
acl_base = ( char * ) ppntace [ i ] ;
2007-10-17 01:35:39 +04:00
acl_size = le16_to_cpu ( ppntace [ i ] - > size ) ;
2007-10-03 22:22:19 +04:00
}
kfree ( ppace ) ;
kfree ( ppntace ) ;
}
return ;
}
2007-09-25 20:17:24 +04:00
static int parse_sid ( struct cifs_sid * psid , char * end_of_acl )
{
2007-10-03 22:22:19 +04:00
2007-09-25 20:17:24 +04:00
/* BB need to add parm so we can store the SID BB */
/* validate that we do not go past end of acl */
if ( end_of_acl < ( char * ) psid + sizeof ( struct cifs_sid ) ) {
2007-10-03 22:22:19 +04:00
cERROR ( 1 , ( " ACL too small to parse SID " ) ) ;
2007-09-25 20:17:24 +04:00
return - EINVAL ;
}
2007-10-03 22:22:19 +04:00
2007-10-16 22:40:37 +04:00
if ( psid - > num_subauth ) {
2007-09-25 20:17:24 +04:00
# ifdef CONFIG_CIFS_DEBUG2
2007-10-12 22:54:12 +04:00
int i ;
2007-10-03 22:22:19 +04:00
cFYI ( 1 , ( " SID revision %d num_auth %d First subauth 0x%x " ,
psid - > revision , psid - > num_subauth , psid - > sub_auth [ 0 ] ) ) ;
2007-09-25 20:17:24 +04:00
2007-10-16 22:40:37 +04:00
for ( i = 0 ; i < psid - > num_subauth ; i + + ) {
2007-10-03 22:22:19 +04:00
cFYI ( 1 , ( " SID sub_auth[%d]: 0x%x " , i ,
2007-10-12 08:11:59 +04:00
le32_to_cpu ( psid - > sub_auth [ i ] ) ) ) ;
2007-10-03 22:22:19 +04:00
}
2007-10-03 23:43:19 +04:00
/* BB add length check to make sure that we do not have huge
2007-10-03 22:22:19 +04:00
num auths and therefore go off the end */
2007-10-03 23:43:19 +04:00
cFYI ( 1 , ( " RID 0x%x " ,
2007-10-16 22:40:37 +04:00
le32_to_cpu ( psid - > sub_auth [ psid - > num_subauth - 1 ] ) ) ) ;
2007-09-25 20:17:24 +04:00
# endif
2007-10-03 22:22:19 +04:00
}
2007-09-25 20:17:24 +04:00
return 0 ;
}
2007-10-03 22:22:19 +04:00
2007-09-25 20:17:24 +04:00
/* Convert CIFS ACL to POSIX form */
int parse_sec_desc ( struct cifs_ntsd * pntsd , int acl_len )
{
2007-10-03 22:22:19 +04:00
int rc ;
2007-09-25 20:17:24 +04:00
struct cifs_sid * owner_sid_ptr , * group_sid_ptr ;
struct cifs_acl * dacl_ptr ; /* no need for SACL ptr */
char * end_of_acl = ( ( char * ) pntsd ) + acl_len ;
owner_sid_ptr = ( struct cifs_sid * ) ( ( char * ) pntsd +
2007-10-16 22:40:37 +04:00
le32_to_cpu ( pntsd - > osidoffset ) ) ;
2007-09-25 20:17:24 +04:00
group_sid_ptr = ( struct cifs_sid * ) ( ( char * ) pntsd +
2007-10-16 22:40:37 +04:00
le32_to_cpu ( pntsd - > gsidoffset ) ) ;
2007-09-25 20:17:24 +04:00
dacl_ptr = ( struct cifs_acl * ) ( ( char * ) pntsd +
2007-10-16 22:40:37 +04:00
le32_to_cpu ( pntsd - > dacloffset ) ) ;
2007-09-25 20:17:24 +04:00
# ifdef CONFIG_CIFS_DEBUG2
cFYI ( 1 , ( " revision %d type 0x%x ooffset 0x%x goffset 0x%x "
" sacloffset 0x%x dacloffset 0x%x " ,
2007-10-16 22:40:37 +04:00
pntsd - > revision , pntsd - > type , le32_to_cpu ( pntsd - > osidoffset ) ,
le32_to_cpu ( pntsd - > gsidoffset ) ,
le32_to_cpu ( pntsd - > sacloffset ) ,
2007-10-17 01:35:39 +04:00
le32_to_cpu ( pntsd - > dacloffset ) ) ) ;
2007-09-25 20:17:24 +04:00
# endif
rc = parse_sid ( owner_sid_ptr , end_of_acl ) ;
if ( rc )
return rc ;
rc = parse_sid ( group_sid_ptr , end_of_acl ) ;
if ( rc )
return rc ;
2007-10-03 22:22:19 +04:00
parse_dacl ( dacl_ptr , end_of_acl ) ;
2007-09-25 20:17:24 +04:00
/* cifscred->uid = owner_sid_ptr->rid;
cifscred - > gid = group_sid_ptr - > rid ;
memcpy ( ( void * ) ( & ( cifscred - > osid ) ) , ( void * ) owner_sid_ptr ,
sizeof ( struct cifs_sid ) ) ;
memcpy ( ( void * ) ( & ( cifscred - > gsid ) ) , ( void * ) group_sid_ptr ,
sizeof ( struct cifs_sid ) ) ; */
2007-10-12 08:11:59 +04:00
2007-09-25 20:17:24 +04:00
return ( 0 ) ;
}
2007-10-12 08:11:59 +04:00
# endif /* CONFIG_CIFS_EXPERIMENTAL */