2006-02-04 01:19:41 +03:00
/*
Unix SMB / CIFS implementation .
Check access based on valid users , read list and friends
Copyright ( C ) Volker Lendecke 2005
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-02-04 01:19:41 +03:00
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-02-04 01:19:41 +03:00
*/
# include "includes.h"
2009-05-26 18:38:45 +04:00
# include "smbd/globals.h"
2006-02-04 01:19:41 +03:00
/*
* No prefix means direct username
* @ name means netgroup first , then unix group
* & name means netgroup
* + name means unix group
* + and & may be combined
*/
2007-10-19 04:40:25 +04:00
static bool do_group_checks ( const char * * name , const char * * pattern )
2006-02-04 01:19:41 +03:00
{
if ( ( * name ) [ 0 ] = = ' @ ' ) {
* pattern = " &+ " ;
* name + = 1 ;
return True ;
}
if ( ( ( * name ) [ 0 ] = = ' + ' ) & & ( ( * name ) [ 1 ] = = ' & ' ) ) {
* pattern = " +& " ;
* name + = 2 ;
return True ;
}
if ( ( * name ) [ 0 ] = = ' + ' ) {
* pattern = " + " ;
* name + = 1 ;
return True ;
}
if ( ( ( * name ) [ 0 ] = = ' & ' ) & & ( ( * name ) [ 1 ] = = ' + ' ) ) {
* pattern = " &+ " ;
* name + = 2 ;
return True ;
}
if ( ( * name ) [ 0 ] = = ' & ' ) {
* pattern = " & " ;
* name + = 1 ;
return True ;
}
return False ;
}
2007-10-19 04:40:25 +04:00
static bool token_contains_name ( TALLOC_CTX * mem_ctx ,
2006-02-04 01:19:41 +03:00
const char * username ,
2008-05-11 03:03:45 +04:00
const char * domain ,
2006-02-04 01:19:41 +03:00
const char * sharename ,
const struct nt_user_token * token ,
const char * name )
{
const char * prefix ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2006-09-08 18:28:06 +04:00
enum lsa_SidType type ;
2009-05-26 18:38:45 +04:00
struct smbd_server_connection * sconn = smbd_server_conn ;
2006-02-04 01:19:41 +03:00
if ( username ! = NULL ) {
2008-05-11 03:03:45 +04:00
name = talloc_sub_basic ( mem_ctx , username , domain , name ) ;
2006-02-04 01:19:41 +03:00
}
if ( sharename ! = NULL ) {
name = talloc_string_sub ( mem_ctx , name , " %S " , sharename ) ;
}
if ( name = = NULL ) {
/* This is too security sensitive, better panic than return a
* result that might be interpreted in a wrong way . */
2007-06-16 01:58:49 +04:00
smb_panic ( " substitutions failed " ) ;
2006-02-04 01:19:41 +03:00
}
2006-03-09 18:51:55 +03:00
/* check to see is we already have a SID */
if ( string_to_sid ( & sid , name ) ) {
DEBUG ( 5 , ( " token_contains_name: Checking for SID [%s] in token \n " , name ) ) ;
return nt_token_check_sid ( & sid , token ) ;
}
2006-02-04 01:19:41 +03:00
if ( ! do_group_checks ( & name , & prefix ) ) {
2006-08-05 01:07:32 +04:00
if ( ! lookup_name_smbconf ( mem_ctx , name , LOOKUP_NAME_ALL ,
2006-02-04 01:19:41 +03:00
NULL , NULL , & sid , & type ) ) {
DEBUG ( 5 , ( " lookup_name %s failed \n " , name ) ) ;
return False ;
}
if ( type ! = SID_NAME_USER ) {
DEBUG ( 5 , ( " %s is a %s, expected a user \n " ,
name , sid_type_lookup ( type ) ) ) ;
return False ;
}
return nt_token_check_sid ( & sid , token ) ;
}
for ( /* initialized above */ ; * prefix ! = ' \0 ' ; prefix + + ) {
if ( * prefix = = ' + ' ) {
2006-08-05 01:07:32 +04:00
if ( ! lookup_name_smbconf ( mem_ctx , name ,
2006-02-04 01:19:41 +03:00
LOOKUP_NAME_ALL | LOOKUP_NAME_GROUP ,
NULL , NULL , & sid , & type ) ) {
DEBUG ( 5 , ( " lookup_name %s failed \n " , name ) ) ;
return False ;
}
if ( ( type ! = SID_NAME_DOM_GRP ) & &
( type ! = SID_NAME_ALIAS ) & &
( type ! = SID_NAME_WKN_GRP ) ) {
DEBUG ( 5 , ( " %s is a %s, expected a group \n " ,
name , sid_type_lookup ( type ) ) ) ;
return False ;
}
if ( nt_token_check_sid ( & sid , token ) ) {
return True ;
}
continue ;
}
if ( * prefix = = ' & ' ) {
2009-08-22 03:17:17 +04:00
if ( username ) {
if ( user_in_netgroup ( sconn , username , name ) ) {
return True ;
}
2006-02-04 01:19:41 +03:00
}
continue ;
}
2007-06-16 01:58:49 +04:00
smb_panic ( " got invalid prefix from do_groups_check " ) ;
2006-02-04 01:19:41 +03:00
}
return False ;
}
/*
* Check whether a user is contained in the list provided .
*
* Please note that the user name and share names passed in here mainly for
* the substitution routines that expand the parameter values , the decision
* whether a user is in the list is done after a lookup_name on the expanded
* parameter value , solely based on comparing the SIDs in token .
*
* The other use is the netgroup check when using @ group or & group .
*/
2007-10-19 04:40:25 +04:00
bool token_contains_name_in_list ( const char * username ,
2008-05-11 03:03:45 +04:00
const char * domain ,
2006-02-04 01:19:41 +03:00
const char * sharename ,
const struct nt_user_token * token ,
const char * * list )
{
TALLOC_CTX * mem_ctx ;
if ( list = = NULL ) {
return False ;
}
2006-03-09 18:51:55 +03:00
if ( ( mem_ctx = talloc_new ( NULL ) ) = = NULL ) {
2007-06-16 01:58:49 +04:00
smb_panic ( " talloc_new failed " ) ;
2006-02-04 01:19:41 +03:00
}
while ( * list ! = NULL ) {
2008-05-11 03:03:45 +04:00
if ( token_contains_name ( mem_ctx , username , domain , sharename ,
token , * list ) ) {
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( mem_ctx ) ;
2006-02-04 01:19:41 +03:00
return True ;
}
list + = 1 ;
}
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( mem_ctx ) ;
2006-02-04 01:19:41 +03:00
return False ;
}
/*
* Check whether the user described by " token " has access to share snum .
*
* This looks at " invalid users " , " valid users " and " only user/username "
*
* Please note that the user name and share names passed in here mainly for
* the substitution routines that expand the parameter values , the decision
* whether a user is in the list is done after a lookup_name on the expanded
* parameter value , solely based on comparing the SIDs in token .
*
* The other use is the netgroup check when using @ group or & group .
*/
2008-05-11 03:03:45 +04:00
bool user_ok_token ( const char * username , const char * domain ,
2008-12-04 22:20:57 +03:00
const struct nt_user_token * token , int snum )
2006-02-04 01:19:41 +03:00
{
if ( lp_invalid_users ( snum ) ! = NULL ) {
2008-05-11 03:03:45 +04:00
if ( token_contains_name_in_list ( username , domain ,
lp_servicename ( snum ) ,
2006-02-04 01:19:41 +03:00
token ,
lp_invalid_users ( snum ) ) ) {
DEBUG ( 10 , ( " User %s in 'invalid users' \n " , username ) ) ;
return False ;
}
}
if ( lp_valid_users ( snum ) ! = NULL ) {
2008-05-11 03:03:45 +04:00
if ( ! token_contains_name_in_list ( username , domain ,
2006-02-04 01:19:41 +03:00
lp_servicename ( snum ) , token ,
lp_valid_users ( snum ) ) ) {
2006-04-30 18:14:46 +04:00
DEBUG ( 10 , ( " User %s not in 'valid users' \n " ,
username ) ) ;
2006-02-04 01:19:41 +03:00
return False ;
}
}
if ( lp_onlyuser ( snum ) ) {
const char * list [ 2 ] ;
list [ 0 ] = lp_username ( snum ) ;
list [ 1 ] = NULL ;
2006-09-30 13:45:53 +04:00
if ( ( list [ 0 ] = = NULL ) | | ( * list [ 0 ] = = ' \0 ' ) ) {
DEBUG ( 0 , ( " 'only user = yes' and no 'username =' \n " ) ) ;
return False ;
}
2008-05-11 03:03:45 +04:00
if ( ! token_contains_name_in_list ( NULL , domain ,
lp_servicename ( snum ) ,
2006-02-04 01:19:41 +03:00
token , list ) ) {
DEBUG ( 10 , ( " %s != 'username' \n " , username ) ) ;
return False ;
}
}
DEBUG ( 10 , ( " user_ok_token: share %s is ok for unix user %s \n " ,
lp_servicename ( snum ) , username ) ) ;
return True ;
}
/*
* Check whether the user described by " token " is restricted to read - only
* access on share snum .
*
* This looks at " invalid users " , " valid users " and " only user/username "
*
* Please note that the user name and share names passed in here mainly for
* the substitution routines that expand the parameter values , the decision
* whether a user is in the list is done after a lookup_name on the expanded
* parameter value , solely based on comparing the SIDs in token .
*
* The other use is the netgroup check when using @ group or & group .
*/
2007-10-19 04:40:25 +04:00
bool is_share_read_only_for_token ( const char * username ,
2008-05-11 03:03:45 +04:00
const char * domain ,
2008-12-04 22:20:57 +03:00
const struct nt_user_token * token ,
2008-11-18 01:13:20 +03:00
connection_struct * conn )
2006-02-04 01:19:41 +03:00
{
2008-11-18 01:13:20 +03:00
int snum = SNUM ( conn ) ;
bool result = conn - > read_only ;
2006-02-04 01:19:41 +03:00
if ( lp_readlist ( snum ) ! = NULL ) {
2008-05-11 03:03:45 +04:00
if ( token_contains_name_in_list ( username , domain ,
2006-02-04 01:19:41 +03:00
lp_servicename ( snum ) , token ,
lp_readlist ( snum ) ) ) {
result = True ;
}
}
if ( lp_writelist ( snum ) ! = NULL ) {
2008-05-11 03:03:45 +04:00
if ( token_contains_name_in_list ( username , domain ,
2006-02-04 01:19:41 +03:00
lp_servicename ( snum ) , token ,
lp_writelist ( snum ) ) ) {
result = False ;
}
}
DEBUG ( 10 , ( " is_share_read_only_for_user: share %s is %s for unix user "
" %s \n " , lp_servicename ( snum ) ,
result ? " read-only " : " read-write " , username ) ) ;
return result ;
}