2006-02-04 01:19:41 +03:00
/*
Samba Unix / Linux SMB client library
Distributed SMB / CIFS Server Management Utility
Copyright ( C ) Jeremy Allison ( jra @ samba . org ) 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
2008-05-10 01:22:12 +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"
# include "utils/net.h"
struct {
const char * us_errstr ;
enum usershare_err us_err ;
} us_errs [ ] = {
{ " " , USERSHARE_OK } ,
{ " Malformed usershare file " , USERSHARE_MALFORMED_FILE } ,
{ " Bad version number " , USERSHARE_BAD_VERSION } ,
{ " Malformed path entry " , USERSHARE_MALFORMED_PATH } ,
{ " Malformed comment entryfile " , USERSHARE_MALFORMED_COMMENT_DEF } ,
{ " Malformed acl definition " , USERSHARE_MALFORMED_ACL_DEF } ,
{ " Acl parse error " , USERSHARE_ACL_ERR } ,
{ " Path not absolute " , USERSHARE_PATH_NOT_ABSOLUTE } ,
{ " Path is denied " , USERSHARE_PATH_IS_DENIED } ,
{ " Path not allowed " , USERSHARE_PATH_NOT_ALLOWED } ,
{ " Path is not a directory " , USERSHARE_PATH_NOT_DIRECTORY } ,
{ " System error " , USERSHARE_POSIX_ERR } ,
{ NULL , ( enum usershare_err ) - 1 }
} ;
static const char * get_us_error_code ( enum usershare_err us_err )
{
2007-11-24 18:32:38 +03:00
char * result ;
2006-02-04 01:19:41 +03:00
int idx = 0 ;
while ( us_errs [ idx ] . us_errstr ! = NULL ) {
if ( us_errs [ idx ] . us_err = = us_err ) {
return us_errs [ idx ] . us_errstr ;
}
idx + + ;
}
2007-11-24 18:32:38 +03:00
result = talloc_asprintf ( talloc_tos ( ) , " Usershare error code (0x%x) " ,
( unsigned int ) us_err ) ;
SMB_ASSERT ( result ! = NULL ) ;
return result ;
2006-02-04 01:19:41 +03:00
}
/* The help subsystem for the USERSHARE subcommand */
2008-05-10 01:22:12 +04:00
static int net_usershare_add_usage ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
2008-05-10 01:22:12 +04:00
char chr = * lp_winbind_separator ( ) ;
2006-02-04 01:19:41 +03:00
d_printf (
2006-04-30 04:36:26 +04:00
" net usershare add [-l|--long] <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>] \n "
2006-02-04 01:19:41 +03:00
" \t Adds the specified share name for this user. \n "
" \t <sharename> is the new share name. \n "
" \t <path> is the path on the filesystem to export. \n "
" \t <comment> is the optional comment for the new share. \n "
" \t <acl> is an optional share acl in the format \" DOMAIN%cname:X,DOMAIN%cname:X,.... \" \n "
2006-04-30 04:36:26 +04:00
" \t <guest_ok=y> if present sets \" guest ok = yes \" on this usershare. \n "
2006-02-04 01:19:41 +03:00
" \t \t \" X \" represents a permission and can be any one of the characters f, r or d \n "
" \t \t where \" f \" means full control, \" r \" means read-only, \" d \" means deny access. \n "
" \t \t name may be a domain user or group. For local users use the local server name "
" instead of \" DOMAIN \" \n "
" \t \t The default acl is \" Everyone:r \" which allows everyone read-only access. \n "
" \t Add -l or --long to print the info on the newly added share. \n " ,
2008-05-10 01:22:12 +04:00
chr , chr ) ;
2006-02-04 01:19:41 +03:00
return - 1 ;
}
2008-05-10 01:22:12 +04:00
static int net_usershare_delete_usage ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
d_printf (
" net usershare delete <sharename> \n " \
" \t deletes the specified share name for this user. \n " ) ;
return - 1 ;
}
2008-05-10 01:22:12 +04:00
static int net_usershare_info_usage ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
d_printf (
" net usershare info [-l|--long] [wildcard sharename] \n " \
" \t Prints out the path, comment and acl elements of shares that match the wildcard. \n "
" \t By default only gives info on shares owned by the current user \n "
" \t Add -l or --long to apply this to all shares \n "
" \t Omit the sharename or use a wildcard of '*' to see all shares \n " ) ;
return - 1 ;
}
2008-05-10 01:22:12 +04:00
static int net_usershare_list_usage ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
d_printf (
" net usershare list [-l|--long] [wildcard sharename] \n " \
" \t Lists the names of all shares that match the wildcard. \n "
" \t By default only lists shares owned by the current user \n "
" \t Add -l or --long to apply this to all shares \n "
" \t Omit the sharename or use a wildcard of '*' to see all shares \n " ) ;
return - 1 ;
}
2008-05-10 01:22:12 +04:00
int net_usershare_usage ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
2006-04-30 04:36:26 +04:00
d_printf ( " net usershare add <sharename> <path> [<comment>] [<acl>] [<guest_ok=[y|n]>] to "
" add or change a user defined share. \n "
2006-02-04 01:19:41 +03:00
" net usershare delete <sharename> to delete a user defined share. \n "
" net usershare info [-l|--long] [wildcard sharename] to print info about a user defined share. \n "
" net usershare list [-l|--long] [wildcard sharename] to list user defined shares. \n "
" net usershare help \n " \
" \n Type \" net usershare help <option> \" to get more information on that option \n \n " ) ;
2008-05-10 01:22:12 +04:00
net_common_flags_usage ( c , argc , argv ) ;
2006-02-04 01:19:41 +03:00
return - 1 ;
}
/***************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-12-04 06:19:19 +03:00
static char * get_basepath ( TALLOC_CTX * ctx )
2006-02-04 01:19:41 +03:00
{
2007-12-04 06:19:19 +03:00
char * basepath = talloc_strdup ( ctx , lp_usershare_path ( ) ) ;
if ( ! basepath ) {
return NULL ;
}
2006-06-15 15:24:01 +04:00
if ( ( basepath [ 0 ] ! = ' \0 ' ) & & ( basepath [ strlen ( basepath ) - 1 ] = = ' / ' ) ) {
2006-02-04 01:19:41 +03:00
basepath [ strlen ( basepath ) - 1 ] = ' \0 ' ;
}
2007-12-04 06:19:19 +03:00
return basepath ;
2006-02-04 01:19:41 +03:00
}
/***************************************************************************
Delete a single userlevel share .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-10 01:22:12 +04:00
static int net_usershare_delete ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
2007-12-04 06:19:19 +03:00
char * us_path ;
2006-02-04 01:19:41 +03:00
char * sharename ;
if ( argc ! = 1 ) {
2008-05-10 01:22:12 +04:00
return net_usershare_delete_usage ( c , argc , argv ) ;
2006-02-04 01:19:41 +03:00
}
2006-06-19 23:07:39 +04:00
if ( ( sharename = strdup_lower ( argv [ 0 ] ) ) = = NULL ) {
d_fprintf ( stderr , " strdup failed \n " ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
if ( ! validate_net_name ( sharename , INVALID_SHARENAME_CHARS , strlen ( sharename ) ) ) {
d_fprintf ( stderr , " net usershare delete: share name %s contains "
" invalid characters (any of %s) \n " ,
sharename , INVALID_SHARENAME_CHARS ) ;
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2007-12-04 06:19:19 +03:00
us_path = talloc_asprintf ( talloc_tos ( ) ,
" %s/%s " ,
lp_usershare_path ( ) ,
sharename ) ;
if ( ! us_path ) {
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
if ( unlink ( us_path ) ! = 0 ) {
d_fprintf ( stderr , " net usershare delete: unable to remove usershare %s. "
" Error was %s \n " ,
us_path , strerror ( errno ) ) ;
SAFE_FREE ( sharename ) ;
return - 1 ;
}
SAFE_FREE ( sharename ) ;
return 0 ;
}
/***************************************************************************
Data structures to handle a list of usershare files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct file_list {
struct file_list * next , * prev ;
const char * pathname ;
} ;
static struct file_list * flist ;
/***************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static int get_share_list ( TALLOC_CTX * ctx , const char * wcard , bool only_ours )
2006-02-04 01:19:41 +03:00
{
SMB_STRUCT_DIR * dp ;
SMB_STRUCT_DIRENT * de ;
uid_t myuid = geteuid ( ) ;
struct file_list * fl = NULL ;
2007-12-04 06:19:19 +03:00
char * basepath = get_basepath ( ctx ) ;
2006-02-04 01:19:41 +03:00
2007-12-04 06:19:19 +03:00
if ( ! basepath ) {
return - 1 ;
}
2006-02-04 01:19:41 +03:00
dp = sys_opendir ( basepath ) ;
if ( ! dp ) {
d_fprintf ( stderr , " get_share_list: cannot open usershare directory %s. Error %s \n " ,
basepath , strerror ( errno ) ) ;
return - 1 ;
}
while ( ( de = sys_readdir ( dp ) ) ! = 0 ) {
SMB_STRUCT_STAT sbuf ;
2007-12-04 06:19:19 +03:00
char * path ;
2006-02-04 01:19:41 +03:00
const char * n = de - > d_name ;
/* Ignore . and .. */
if ( * n = = ' . ' ) {
if ( ( n [ 1 ] = = ' \0 ' ) | | ( n [ 1 ] = = ' . ' & & n [ 2 ] = = ' \0 ' ) ) {
continue ;
}
}
if ( ! validate_net_name ( n , INVALID_SHARENAME_CHARS , strlen ( n ) ) ) {
d_fprintf ( stderr , " get_share_list: ignoring bad share name %s \n " , n ) ;
continue ;
}
2007-12-04 06:19:19 +03:00
path = talloc_asprintf ( ctx ,
" %s/%s " ,
basepath ,
n ) ;
if ( ! path ) {
sys_closedir ( dp ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
if ( sys_lstat ( path , & sbuf ) ! = 0 ) {
d_fprintf ( stderr , " get_share_list: can't lstat file %s. Error was %s \n " ,
path , strerror ( errno ) ) ;
continue ;
}
if ( ! S_ISREG ( sbuf . st_mode ) ) {
d_fprintf ( stderr , " get_share_list: file %s is not a regular file. Ignoring. \n " ,
path ) ;
continue ;
}
if ( only_ours & & sbuf . st_uid ! = myuid ) {
continue ;
}
if ( ! unix_wild_match ( wcard , n ) ) {
continue ;
}
2007-12-04 06:19:19 +03:00
/* (Finally) - add to list. */
2006-02-04 01:19:41 +03:00
fl = TALLOC_P ( ctx , struct file_list ) ;
if ( ! fl ) {
2007-12-04 06:19:19 +03:00
sys_closedir ( dp ) ;
2006-02-04 01:19:41 +03:00
return - 1 ;
}
fl - > pathname = talloc_strdup ( ctx , n ) ;
if ( ! fl - > pathname ) {
2007-12-04 06:19:19 +03:00
sys_closedir ( dp ) ;
2006-02-04 01:19:41 +03:00
return - 1 ;
}
DLIST_ADD ( flist , fl ) ;
}
sys_closedir ( dp ) ;
return 0 ;
}
2006-06-16 22:50:01 +04:00
enum us_priv_op { US_LIST_OP , US_INFO_OP } ;
2006-02-04 01:19:41 +03:00
2006-06-16 22:50:01 +04:00
struct us_priv_info {
2006-02-04 01:19:41 +03:00
TALLOC_CTX * ctx ;
2006-06-16 22:50:01 +04:00
enum us_priv_op op ;
2008-05-10 01:22:12 +04:00
struct net_context * c ;
2006-02-04 01:19:41 +03:00
} ;
/***************************************************************************
Call a function for every share on the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-02-06 21:03:57 +03:00
static int process_share_list ( int ( * fn ) ( struct file_list * , void * ) , void * priv )
2006-02-04 01:19:41 +03:00
{
struct file_list * fl ;
int ret = 0 ;
for ( fl = flist ; fl ; fl = fl - > next ) {
2006-02-06 21:03:57 +03:00
ret = ( * fn ) ( fl , priv ) ;
2006-02-04 01:19:41 +03:00
}
return ret ;
}
/***************************************************************************
Info function .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-02-06 21:03:57 +03:00
static int info_fn ( struct file_list * fl , void * priv )
2006-02-04 01:19:41 +03:00
{
SMB_STRUCT_STAT sbuf ;
char * * lines = NULL ;
2006-06-16 22:50:01 +04:00
struct us_priv_info * pi = ( struct us_priv_info * ) priv ;
2006-02-04 01:19:41 +03:00
TALLOC_CTX * ctx = pi - > ctx ;
2008-05-10 01:22:12 +04:00
struct net_context * c = pi - > c ;
2006-02-04 01:19:41 +03:00
int fd = - 1 ;
int numlines = 0 ;
SEC_DESC * psd = NULL ;
2007-12-04 06:19:19 +03:00
char * basepath ;
2007-11-14 05:42:42 +03:00
char * sharepath = NULL ;
char * comment = NULL ;
2007-12-04 06:19:19 +03:00
char * acl_str ;
2006-02-04 01:19:41 +03:00
int num_aces ;
char sep_str [ 2 ] ;
enum usershare_err us_err ;
2007-10-19 04:40:25 +04:00
bool guest_ok = False ;
2006-02-04 01:19:41 +03:00
sep_str [ 0 ] = * lp_winbind_separator ( ) ;
sep_str [ 1 ] = ' \0 ' ;
2007-12-04 06:19:19 +03:00
basepath = get_basepath ( ctx ) ;
if ( ! basepath ) {
return - 1 ;
}
basepath = talloc_asprintf_append ( basepath ,
" /%s " ,
fl - > pathname ) ;
if ( ! basepath ) {
return - 1 ;
}
2006-02-04 01:19:41 +03:00
# ifdef O_NOFOLLOW
fd = sys_open ( basepath , O_RDONLY | O_NOFOLLOW , 0 ) ;
# else
fd = sys_open ( basepath , O_RDONLY , 0 ) ;
# endif
if ( fd = = - 1 ) {
d_fprintf ( stderr , " info_fn: unable to open %s. %s \n " ,
basepath , strerror ( errno ) ) ;
return - 1 ;
}
/* Paranoia... */
if ( sys_fstat ( fd , & sbuf ) ! = 0 ) {
d_fprintf ( stderr , " info_fn: can't fstat file %s. Error was %s \n " ,
basepath , strerror ( errno ) ) ;
close ( fd ) ;
return - 1 ;
}
if ( ! S_ISREG ( sbuf . st_mode ) ) {
d_fprintf ( stderr , " info_fn: file %s is not a regular file. Ignoring. \n " ,
basepath ) ;
close ( fd ) ;
return - 1 ;
}
lines = fd_lines_load ( fd , & numlines , 10240 ) ;
close ( fd ) ;
if ( lines = = NULL ) {
return - 1 ;
}
/* Ensure it's well formed. */
us_err = parse_usershare_file ( ctx , & sbuf , fl - > pathname , - 1 , lines , numlines ,
2007-11-14 05:42:42 +03:00
& sharepath ,
& comment ,
2006-04-30 04:36:26 +04:00
& psd ,
& guest_ok ) ;
2006-02-04 01:19:41 +03:00
2006-03-08 11:28:42 +03:00
file_lines_free ( lines ) ;
2006-02-04 01:19:41 +03:00
if ( us_err ! = USERSHARE_OK ) {
d_fprintf ( stderr , " info_fn: file %s is not a well formed usershare file. \n " ,
basepath ) ;
d_fprintf ( stderr , " info_fn: Error was %s. \n " ,
get_us_error_code ( us_err ) ) ;
return - 1 ;
}
2007-12-04 06:19:19 +03:00
acl_str = talloc_strdup ( ctx , " usershare_acl= " ) ;
if ( ! acl_str ) {
return - 1 ;
}
2006-02-04 01:19:41 +03:00
for ( num_aces = 0 ; num_aces < psd - > dacl - > num_aces ; num_aces + + ) {
const char * domain ;
const char * name ;
2006-02-15 05:07:14 +03:00
NTSTATUS ntstatus ;
2006-02-04 01:19:41 +03:00
2008-05-10 01:22:12 +04:00
ntstatus = net_lookup_name_from_sid ( c , ctx ,
& psd - > dacl - > aces [ num_aces ] . trustee ,
& domain , & name ) ;
2006-02-15 05:07:14 +03:00
2006-02-21 20:00:00 +03:00
if ( NT_STATUS_IS_OK ( ntstatus ) ) {
if ( domain & & * domain ) {
2007-12-04 06:19:19 +03:00
acl_str = talloc_asprintf_append ( acl_str ,
" %s%s " ,
domain ,
sep_str ) ;
if ( ! acl_str ) {
return - 1 ;
}
2006-02-04 01:19:41 +03:00
}
2007-12-04 06:19:19 +03:00
acl_str = talloc_asprintf_append ( acl_str ,
" %s " ,
name ) ;
if ( ! acl_str ) {
return - 1 ;
}
2006-02-04 01:19:41 +03:00
} else {
fstring sidstr ;
2007-12-16 00:47:30 +03:00
sid_to_fstring ( sidstr ,
& psd - > dacl - > aces [ num_aces ] . trustee ) ;
2007-12-04 06:19:19 +03:00
acl_str = talloc_asprintf_append ( acl_str ,
" %s " ,
sidstr ) ;
if ( ! acl_str ) {
return - 1 ;
}
}
acl_str = talloc_asprintf_append ( acl_str , " : " ) ;
if ( ! acl_str ) {
return - 1 ;
2006-02-04 01:19:41 +03:00
}
2006-09-21 02:23:12 +04:00
if ( psd - > dacl - > aces [ num_aces ] . type = = SEC_ACE_TYPE_ACCESS_DENIED ) {
2007-12-04 06:19:19 +03:00
acl_str = talloc_asprintf_append ( acl_str , " D, " ) ;
if ( ! acl_str ) {
return - 1 ;
}
2006-02-04 01:19:41 +03:00
} else {
2006-09-21 02:23:12 +04:00
if ( psd - > dacl - > aces [ num_aces ] . access_mask & GENERIC_ALL_ACCESS ) {
2007-12-04 06:19:19 +03:00
acl_str = talloc_asprintf_append ( acl_str , " F, " ) ;
2006-02-04 01:19:41 +03:00
} else {
2007-12-04 06:19:19 +03:00
acl_str = talloc_asprintf_append ( acl_str , " R, " ) ;
}
if ( ! acl_str ) {
return - 1 ;
2006-02-04 01:19:41 +03:00
}
}
}
if ( pi - > op = = US_INFO_OP ) {
d_printf ( " [%s] \n " , fl - > pathname ) ;
d_printf ( " path=%s \n " , sharepath ) ;
d_printf ( " comment=%s \n " , comment ) ;
2006-04-30 04:36:26 +04:00
d_printf ( " %s \n " , acl_str ) ;
d_printf ( " guest_ok=%c \n \n " , guest_ok ? ' y ' : ' n ' ) ;
2006-02-04 01:19:41 +03:00
} else if ( pi - > op = = US_LIST_OP ) {
d_printf ( " %s \n " , fl - > pathname ) ;
}
return 0 ;
}
/***************************************************************************
Print out info ( internal detail ) on userlevel shares .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-10 01:22:12 +04:00
static int net_usershare_info ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
fstring wcard ;
2007-10-19 04:40:25 +04:00
bool only_ours = True ;
2006-02-04 01:19:41 +03:00
int ret = - 1 ;
2006-06-16 22:50:01 +04:00
struct us_priv_info pi ;
2006-02-04 01:19:41 +03:00
TALLOC_CTX * ctx ;
fstrcpy ( wcard , " * " ) ;
2008-05-10 01:22:12 +04:00
if ( c - > opt_long_list_entries ) {
2006-02-04 01:19:41 +03:00
only_ours = False ;
}
switch ( argc ) {
case 0 :
break ;
case 1 :
fstrcpy ( wcard , argv [ 0 ] ) ;
break ;
default :
2008-05-10 01:22:12 +04:00
return net_usershare_info_usage ( c , argc , argv ) ;
2006-02-04 01:19:41 +03:00
}
strlower_m ( wcard ) ;
ctx = talloc_init ( " share_info " ) ;
ret = get_share_list ( ctx , wcard , only_ours ) ;
if ( ret ) {
return ret ;
}
pi . ctx = ctx ;
pi . op = US_INFO_OP ;
2008-05-10 01:22:12 +04:00
pi . c = c ;
2006-02-04 01:19:41 +03:00
ret = process_share_list ( info_fn , & pi ) ;
talloc_destroy ( ctx ) ;
return ret ;
}
2006-09-06 04:35:27 +04:00
/***************************************************************************
Count the current total number of usershares .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int count_num_usershares ( void )
{
SMB_STRUCT_DIR * dp ;
SMB_STRUCT_DIRENT * de ;
int num_usershares = 0 ;
2007-12-04 06:19:19 +03:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
char * basepath = get_basepath ( ctx ) ;
if ( ! basepath ) {
return - 1 ;
}
2006-09-06 04:35:27 +04:00
dp = sys_opendir ( basepath ) ;
if ( ! dp ) {
d_fprintf ( stderr , " count_num_usershares: cannot open usershare directory %s. Error %s \n " ,
basepath , strerror ( errno ) ) ;
return - 1 ;
}
while ( ( de = sys_readdir ( dp ) ) ! = 0 ) {
SMB_STRUCT_STAT sbuf ;
2007-12-04 06:19:19 +03:00
char * path ;
2006-09-06 04:35:27 +04:00
const char * n = de - > d_name ;
/* Ignore . and .. */
if ( * n = = ' . ' ) {
if ( ( n [ 1 ] = = ' \0 ' ) | | ( n [ 1 ] = = ' . ' & & n [ 2 ] = = ' \0 ' ) ) {
continue ;
}
}
if ( ! validate_net_name ( n , INVALID_SHARENAME_CHARS , strlen ( n ) ) ) {
d_fprintf ( stderr , " count_num_usershares: ignoring bad share name %s \n " , n ) ;
continue ;
}
2007-12-04 06:19:19 +03:00
path = talloc_asprintf ( ctx ,
" %s/%s " ,
basepath ,
n ) ;
if ( ! path ) {
sys_closedir ( dp ) ;
return - 1 ;
}
2006-09-06 04:35:27 +04:00
if ( sys_lstat ( path , & sbuf ) ! = 0 ) {
d_fprintf ( stderr , " count_num_usershares: can't lstat file %s. Error was %s \n " ,
path , strerror ( errno ) ) ;
continue ;
}
if ( ! S_ISREG ( sbuf . st_mode ) ) {
d_fprintf ( stderr , " count_num_usershares: file %s is not a regular file. Ignoring. \n " ,
path ) ;
continue ;
}
num_usershares + + ;
}
sys_closedir ( dp ) ;
return num_usershares ;
}
2006-02-04 01:19:41 +03:00
/***************************************************************************
Add a single userlevel share .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-10 01:22:12 +04:00
static int net_usershare_add ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
2007-12-04 06:19:19 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
2006-02-04 01:19:41 +03:00
SMB_STRUCT_STAT sbuf ;
SMB_STRUCT_STAT lsbuf ;
char * sharename ;
2007-12-04 06:19:19 +03:00
char * full_path ;
char * full_path_tmp ;
2006-02-04 01:19:41 +03:00
const char * us_path ;
const char * us_comment ;
const char * arg_acl ;
char * us_acl ;
char * file_img ;
int num_aces = 0 ;
int i ;
int tmpfd ;
const char * pacl ;
size_t to_write ;
uid_t myeuid = geteuid ( ) ;
2007-10-19 04:40:25 +04:00
bool guest_ok = False ;
2006-09-06 04:35:27 +04:00
int num_usershares ;
2006-02-04 01:19:41 +03:00
us_comment = " " ;
arg_acl = " S-1-1-0:R " ;
switch ( argc ) {
case 0 :
case 1 :
default :
2008-05-10 01:22:12 +04:00
return net_usershare_add_usage ( c , argc , argv ) ;
2006-02-04 01:19:41 +03:00
case 2 :
sharename = strdup_lower ( argv [ 0 ] ) ;
us_path = argv [ 1 ] ;
break ;
case 3 :
sharename = strdup_lower ( argv [ 0 ] ) ;
us_path = argv [ 1 ] ;
us_comment = argv [ 2 ] ;
break ;
case 4 :
sharename = strdup_lower ( argv [ 0 ] ) ;
us_path = argv [ 1 ] ;
us_comment = argv [ 2 ] ;
arg_acl = argv [ 3 ] ;
break ;
2006-04-30 04:36:26 +04:00
case 5 :
sharename = strdup_lower ( argv [ 0 ] ) ;
us_path = argv [ 1 ] ;
us_comment = argv [ 2 ] ;
arg_acl = argv [ 3 ] ;
2007-02-01 19:22:07 +03:00
if ( strlen ( arg_acl ) = = 0 ) {
arg_acl = " S-1-1-0:R " ;
}
2006-04-30 04:36:26 +04:00
if ( ! strnequal ( argv [ 4 ] , " guest_ok= " , 9 ) ) {
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2008-05-10 01:22:12 +04:00
return net_usershare_add_usage ( c , argc , argv ) ;
2006-04-30 04:36:26 +04:00
}
switch ( argv [ 4 ] [ 9 ] ) {
case ' y ' :
case ' Y ' :
guest_ok = True ;
break ;
case ' n ' :
case ' N ' :
guest_ok = False ;
break ;
2007-12-04 06:19:19 +03:00
default :
TALLOC_FREE ( ctx ) ;
2008-05-10 01:22:12 +04:00
return net_usershare_add_usage ( c , argc , argv ) ;
2006-04-30 04:36:26 +04:00
}
break ;
2006-02-04 01:19:41 +03:00
}
2006-09-06 04:35:27 +04:00
/* Ensure we're under the "usershare max shares" number. Advisory only. */
num_usershares = count_num_usershares ( ) ;
2007-02-01 19:22:07 +03:00
if ( num_usershares > = lp_usershare_max_shares ( ) ) {
d_fprintf ( stderr , " net usershare add: maximum number of allowed usershares (%d) reached \n " ,
lp_usershare_max_shares ( ) ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-09-06 04:35:27 +04:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
if ( ! validate_net_name ( sharename , INVALID_SHARENAME_CHARS , strlen ( sharename ) ) ) {
d_fprintf ( stderr , " net usershare add: share name %s contains "
" invalid characters (any of %s) \n " ,
sharename , INVALID_SHARENAME_CHARS ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Disallow shares the same as users. */
if ( getpwnam ( sharename ) ) {
d_fprintf ( stderr , " net usershare add: share name %s is already a valid system user name \n " ,
sharename ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Construct the full path for the usershare file. */
2007-12-04 06:19:19 +03:00
full_path = get_basepath ( ctx ) ;
if ( ! full_path ) {
TALLOC_FREE ( ctx ) ;
SAFE_FREE ( sharename ) ;
return - 1 ;
}
full_path_tmp = talloc_asprintf ( ctx ,
" %s/:tmpXXXXXX " ,
full_path ) ;
if ( ! full_path_tmp ) {
TALLOC_FREE ( ctx ) ;
SAFE_FREE ( sharename ) ;
return - 1 ;
}
full_path = talloc_asprintf_append ( full_path ,
" /%s " ,
sharename ) ;
if ( ! full_path ) {
TALLOC_FREE ( ctx ) ;
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
/* The path *must* be absolute. */
if ( us_path [ 0 ] ! = ' / ' ) {
d_fprintf ( stderr , " net usershare add: path %s is not an absolute path. \n " ,
us_path ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Check the directory to be shared exists. */
if ( sys_stat ( us_path , & sbuf ) ! = 0 ) {
d_fprintf ( stderr , " net usershare add: cannot stat path %s to ensure "
" this is a directory. Error was %s \n " ,
us_path , strerror ( errno ) ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
if ( ! S_ISDIR ( sbuf . st_mode ) ) {
d_fprintf ( stderr , " net usershare add: path %s is not a directory. \n " ,
us_path ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* If we're not root, check if we're restricted to sharing out directories
that we own only . */
if ( ( myeuid ! = 0 ) & & lp_usershare_owner_only ( ) & & ( myeuid ! = sbuf . st_uid ) ) {
d_fprintf ( stderr , " net usershare add: cannot share path %s as "
2006-02-15 05:07:14 +03:00
" we are restricted to only sharing directories we own. \n "
" \t Ask the administrator to add the line \" usershare owner only = False \" \n "
" \t to the [global] section of the smb.conf to allow this. \n " ,
2006-02-04 01:19:41 +03:00
us_path ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* No validation needed on comment. Now go through and validate the
acl string . Convert names to SID ' s as needed . Then run it through
parse_usershare_acl to ensure it ' s valid . */
/* Start off the string we'll append to. */
us_acl = talloc_strdup ( ctx , " " ) ;
2007-12-04 06:19:19 +03:00
if ( ! us_acl ) {
TALLOC_FREE ( ctx ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
pacl = arg_acl ;
num_aces = 1 ;
/* Add the number of ',' characters to get the number of aces. */
num_aces + = count_chars ( pacl , ' , ' ) ;
for ( i = 0 ; i < num_aces ; i + + ) {
DOM_SID sid ;
const char * pcolon = strchr_m ( pacl , ' : ' ) ;
const char * name ;
if ( pcolon = = NULL ) {
d_fprintf ( stderr , " net usershare add: malformed acl %s (missing ':'). \n " ,
pacl ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
switch ( pcolon [ 1 ] ) {
case ' f ' :
case ' F ' :
case ' d ' :
case ' r ' :
case ' R ' :
break ;
default :
d_fprintf ( stderr , " net usershare add: malformed acl %s "
" (access control must be 'r', 'f', or 'd') \n " ,
pacl ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
if ( pcolon [ 2 ] ! = ' , ' & & pcolon [ 2 ] ! = ' \0 ' ) {
d_fprintf ( stderr , " net usershare add: malformed terminating character for acl %s \n " ,
pacl ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Get the name */
2006-06-19 23:07:39 +04:00
if ( ( name = talloc_strndup ( ctx , pacl , pcolon - pacl ) ) = = NULL ) {
d_fprintf ( stderr , " talloc_strndup failed \n " ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-06-19 23:07:39 +04:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
if ( ! string_to_sid ( & sid , name ) ) {
/* Convert to a SID */
2008-05-10 01:22:12 +04:00
NTSTATUS ntstatus = net_lookup_sid_from_name ( c , ctx , name , & sid ) ;
2006-02-15 05:07:14 +03:00
if ( ! NT_STATUS_IS_OK ( ntstatus ) ) {
d_fprintf ( stderr , " net usershare add: cannot convert name \" %s \" to a SID. %s. " ,
name , get_friendly_nt_error_msg ( ntstatus ) ) ;
if ( NT_STATUS_EQUAL ( ntstatus , NT_STATUS_CONNECTION_REFUSED ) ) {
d_fprintf ( stderr , " Maybe smbd is not running. \n " ) ;
} else {
d_fprintf ( stderr , " \n " ) ;
}
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
}
2007-12-15 23:53:26 +03:00
us_acl = talloc_asprintf_append (
us_acl , " %s:%c, " , sid_string_tos ( & sid ) , pcolon [ 1 ] ) ;
2006-02-04 01:19:41 +03:00
/* Move to the next ACL entry. */
if ( pcolon [ 2 ] = = ' , ' ) {
pacl = & pcolon [ 3 ] ;
}
}
/* Remove the last ',' */
us_acl [ strlen ( us_acl ) - 1 ] = ' \0 ' ;
2006-04-30 04:36:26 +04:00
if ( guest_ok & & ! lp_usershare_allow_guests ( ) ) {
d_fprintf ( stderr , " net usershare add: guest_ok=y requested "
" but the \" usershare allow guests \" parameter is not enabled "
" by this server. \n " ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-04-30 04:36:26 +04:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2006-02-04 01:19:41 +03:00
/* Create a temporary filename for this share. */
tmpfd = smb_mkstemp ( full_path_tmp ) ;
if ( tmpfd = = - 1 ) {
d_fprintf ( stderr , " net usershare add: cannot create tmp file %s \n " ,
full_path_tmp ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Ensure we opened the file we thought we did. */
if ( sys_lstat ( full_path_tmp , & lsbuf ) ! = 0 ) {
d_fprintf ( stderr , " net usershare add: cannot lstat tmp file %s \n " ,
full_path_tmp ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Check this is the same as the file we opened. */
if ( sys_fstat ( tmpfd , & sbuf ) ! = 0 ) {
d_fprintf ( stderr , " net usershare add: cannot fstat tmp file %s \n " ,
full_path_tmp ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
if ( ! S_ISREG ( sbuf . st_mode ) | | sbuf . st_dev ! = lsbuf . st_dev | | sbuf . st_ino ! = lsbuf . st_ino ) {
d_fprintf ( stderr , " net usershare add: tmp file %s is not a regular file ? \n " ,
full_path_tmp ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
2007-12-04 06:19:19 +03:00
2006-02-04 01:19:41 +03:00
if ( fchmod ( tmpfd , 0644 ) = = - 1 ) {
d_fprintf ( stderr , " net usershare add: failed to fchmod tmp file %s to 0644n " ,
full_path_tmp ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Create the in-memory image of the file. */
2006-04-30 04:36:26 +04:00
file_img = talloc_strdup ( ctx , " #VERSION 2 \n path= " ) ;
file_img = talloc_asprintf_append ( file_img , " %s \n comment=%s \n usershare_acl=%s \n guest_ok=%c \n " ,
us_path , us_comment , us_acl , guest_ok ? ' y ' : ' n ' ) ;
2006-02-04 01:19:41 +03:00
to_write = strlen ( file_img ) ;
if ( write ( tmpfd , file_img , to_write ) ! = to_write ) {
d_fprintf ( stderr , " net usershare add: failed to write %u bytes to file %s. Error was %s \n " ,
( unsigned int ) to_write , full_path_tmp , strerror ( errno ) ) ;
unlink ( full_path_tmp ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
SAFE_FREE ( sharename ) ;
return - 1 ;
}
/* Attempt to replace any existing share by this name. */
if ( rename ( full_path_tmp , full_path ) ! = 0 ) {
unlink ( full_path_tmp ) ;
d_fprintf ( stderr , " net usershare add: failed to add share %s. Error was %s \n " ,
sharename , strerror ( errno ) ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
close ( tmpfd ) ;
SAFE_FREE ( sharename ) ;
return - 1 ;
}
close ( tmpfd ) ;
2008-05-10 01:22:12 +04:00
if ( c - > opt_long_list_entries ) {
2006-02-04 01:19:41 +03:00
const char * my_argv [ 2 ] ;
my_argv [ 0 ] = sharename ;
my_argv [ 1 ] = NULL ;
2008-05-10 01:22:12 +04:00
net_usershare_info ( c , 1 , my_argv ) ;
2006-02-04 01:19:41 +03:00
}
SAFE_FREE ( sharename ) ;
2007-12-04 06:19:19 +03:00
TALLOC_FREE ( ctx ) ;
2006-02-04 01:19:41 +03:00
return 0 ;
}
#if 0
/***************************************************************************
List function .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-02-06 21:03:57 +03:00
static int list_fn ( struct file_list * fl , void * priv )
2006-02-04 01:19:41 +03:00
{
d_printf ( " %s \n " , fl - > pathname ) ;
return 0 ;
}
# endif
/***************************************************************************
List userlevel shares .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-10 01:22:12 +04:00
static int net_usershare_list ( struct net_context * c , int argc ,
const char * * argv )
2006-02-04 01:19:41 +03:00
{
fstring wcard ;
2007-10-19 04:40:25 +04:00
bool only_ours = True ;
2006-02-04 01:19:41 +03:00
int ret = - 1 ;
2006-06-16 22:50:01 +04:00
struct us_priv_info pi ;
2006-02-04 01:19:41 +03:00
TALLOC_CTX * ctx ;
fstrcpy ( wcard , " * " ) ;
2008-05-10 01:22:12 +04:00
if ( c - > opt_long_list_entries ) {
2006-02-04 01:19:41 +03:00
only_ours = False ;
}
switch ( argc ) {
case 0 :
break ;
case 1 :
fstrcpy ( wcard , argv [ 0 ] ) ;
break ;
default :
2008-05-10 01:22:12 +04:00
return net_usershare_list_usage ( c , argc , argv ) ;
2006-02-04 01:19:41 +03:00
}
strlower_m ( wcard ) ;
ctx = talloc_init ( " share_list " ) ;
ret = get_share_list ( ctx , wcard , only_ours ) ;
if ( ret ) {
return ret ;
}
pi . ctx = ctx ;
pi . op = US_LIST_OP ;
ret = process_share_list ( info_fn , & pi ) ;
talloc_destroy ( ctx ) ;
return ret ;
}
/***************************************************************************
Handle " net usershare help * " subcommands .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-10 01:22:12 +04:00
int net_usershare_help ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
struct functable func [ ] = {
{ " ADD " , net_usershare_add_usage } ,
{ " DELETE " , net_usershare_delete_usage } ,
{ " INFO " , net_usershare_info_usage } ,
{ " LIST " , net_usershare_list_usage } ,
{ NULL , NULL } } ;
2008-05-10 01:22:12 +04:00
return net_run_function ( c , argc , argv , func , net_usershare_usage ) ;
2006-02-04 01:19:41 +03:00
}
/***************************************************************************
Entry - point for all the USERSHARE functions .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-10 01:22:12 +04:00
int net_usershare ( struct net_context * c , int argc , const char * * argv )
2006-02-04 01:19:41 +03:00
{
SMB_STRUCT_DIR * dp ;
struct functable func [ ] = {
{ " ADD " , net_usershare_add } ,
{ " DELETE " , net_usershare_delete } ,
{ " INFO " , net_usershare_info } ,
{ " LIST " , net_usershare_list } ,
{ " HELP " , net_usershare_help } ,
{ NULL , NULL }
} ;
if ( lp_usershare_max_shares ( ) = = 0 ) {
d_fprintf ( stderr , " net usershare: usershares are currently disabled \n " ) ;
return - 1 ;
}
dp = sys_opendir ( lp_usershare_path ( ) ) ;
if ( ! dp ) {
int err = errno ;
d_fprintf ( stderr , " net usershare: cannot open usershare directory %s. Error %s \n " ,
lp_usershare_path ( ) , strerror ( err ) ) ;
if ( err = = EACCES ) {
d_fprintf ( stderr , " You do not have permission to create a usershare. Ask your "
" administrator to grant you permissions to create a share. \n " ) ;
} else if ( err = = ENOENT ) {
d_fprintf ( stderr , " Please ask your system administrator to "
" enable user sharing. \n " ) ;
}
return - 1 ;
}
sys_closedir ( dp ) ;
2008-05-10 01:22:12 +04:00
return net_run_function ( c , argc , argv , func , net_usershare_usage ) ;
2006-02-04 01:19:41 +03:00
}