1996-05-04 11:50:46 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-04 11:50:46 +04:00
Samba system utilities
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
2005-05-09 18:05:10 +04:00
Copyright ( C ) Jeremy Allison 1998 - 2005
Copyright ( C ) Timur Bakeyev 2005
2007-08-10 13:44:13 +04:00
Copyright ( C ) Bjoern Jacke 2006 - 2007
2009-05-14 14:13:24 +04:00
1996-05-04 11:50:46 +04:00
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
1996-05-04 11:50:46 +04:00
( at your option ) any later version .
2009-05-14 14:13:24 +04:00
1996-05-04 11:50:46 +04:00
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 .
2009-05-14 14:13:24 +04:00
1996-05-04 11:50:46 +04:00
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/>.
1996-05-04 11:50:46 +04:00
*/
# include "includes.h"
2011-02-25 18:19:10 +03:00
# include "system/syslog.h"
2011-02-25 18:39:14 +03:00
# include "system/capability.h"
2011-02-25 19:14:22 +03:00
# include "system/passwd.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2012-06-28 22:59:51 +04:00
# include "../lib/util/setid.h"
1996-05-04 11:50:46 +04:00
2012-01-06 03:48:24 +04:00
# ifdef HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
# endif
2006-03-23 02:49:09 +03:00
# ifdef HAVE_SYS_PRCTL_H
# include <sys/prctl.h>
# endif
1996-05-04 11:50:46 +04:00
/*
The idea is that this file will eventually have wrappers around all
1996-06-19 17:23:46 +04:00
important system calls in samba . The aims are :
1996-05-04 11:50:46 +04:00
- to enable easier porting by putting OS dependent stuff in here
- to allow for hooks into other " pseudo-filesystems "
- to allow easier integration of things like the japanese extensions
1996-06-19 17:23:46 +04:00
- to support the philosophy of Samba to expose the features of
the OS within the SMB model . In general whatever file / printer / variable
expansions / etc make sense to the OS should be acceptable to Samba .
1996-05-04 11:50:46 +04:00
*/
2000-06-11 09:57:58 +04:00
2002-07-15 14:35:28 +04:00
/*******************************************************************
A read wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_read ( int fd , void * buf , size_t count )
{
ssize_t ret ;
do {
ret = read ( fd , buf , count ) ;
2010-12-15 02:30:06 +03:00
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
2002-07-15 14:35:28 +04:00
return ret ;
}
/*******************************************************************
A write wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_write ( int fd , const void * buf , size_t count )
{
ssize_t ret ;
do {
ret = write ( fd , buf , count ) ;
2010-12-15 02:30:06 +03:00
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
2002-07-15 14:35:28 +04:00
return ret ;
}
2008-12-22 01:22:30 +03:00
/*******************************************************************
A writev wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_writev ( int fd , const struct iovec * iov , int iovcnt )
{
ssize_t ret ;
2008-12-23 00:42:44 +03:00
#if 0
/* Try to confuse write_data_iov a bit */
if ( ( random ( ) % 5 ) = = 0 ) {
return sys_write ( fd , iov [ 0 ] . iov_base , iov [ 0 ] . iov_len ) ;
}
if ( iov [ 0 ] . iov_len > 1 ) {
return sys_write ( fd , iov [ 0 ] . iov_base ,
( random ( ) % ( iov [ 0 ] . iov_len - 1 ) ) + 1 ) ;
}
# endif
2008-12-22 01:22:30 +03:00
do {
ret = writev ( fd , iov , iovcnt ) ;
2010-12-15 02:30:06 +03:00
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
2008-12-22 01:22:30 +03:00
return ret ;
}
2004-01-06 04:22:14 +03:00
/*******************************************************************
2012-03-28 02:49:48 +04:00
A pread wrapper that will deal with EINTR
2004-01-06 04:22:14 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-03-28 02:49:48 +04:00
# if defined(HAVE_PREAD)
2012-04-05 08:53:08 +04:00
ssize_t sys_pread ( int fd , void * buf , size_t count , off_t off )
2004-01-06 04:22:14 +03:00
{
ssize_t ret ;
do {
ret = pread ( fd , buf , count , off ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
return ret ;
}
# endif
/*******************************************************************
2012-03-28 02:49:48 +04:00
A write wrapper that will deal with EINTR
2004-01-06 04:22:14 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-03-28 02:49:48 +04:00
# if defined(HAVE_PWRITE)
2012-04-05 08:53:08 +04:00
ssize_t sys_pwrite ( int fd , const void * buf , size_t count , off_t off )
2004-01-06 04:22:14 +03:00
{
ssize_t ret ;
do {
ret = pwrite ( fd , buf , count , off ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
return ret ;
}
# endif
2002-07-15 14:35:28 +04:00
/*******************************************************************
2010-12-15 02:30:06 +03:00
A send wrapper that will deal with EINTR or EAGAIN or EWOULDBLOCK .
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_send ( int s , const void * msg , size_t len , int flags )
{
ssize_t ret ;
do {
ret = send ( s , msg , len , flags ) ;
2010-12-15 02:30:06 +03:00
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
2002-07-15 14:35:28 +04:00
return ret ;
}
/*******************************************************************
A recvfrom wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t sys_recvfrom ( int s , void * buf , size_t len , int flags , struct sockaddr * from , socklen_t * fromlen )
{
ssize_t ret ;
do {
ret = recvfrom ( s , buf , len , flags , from , fromlen ) ;
2010-12-15 02:30:06 +03:00
# if defined(EWOULDBLOCK)
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN | | errno = = EWOULDBLOCK ) ) ;
# else
} while ( ret = = - 1 & & ( errno = = EINTR | | errno = = EAGAIN ) ) ;
# endif
2002-07-15 14:35:28 +04:00
return ret ;
}
/*******************************************************************
A fcntl wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_fcntl_ptr ( int fd , int cmd , void * arg )
{
int ret ;
do {
ret = fcntl ( fd , cmd , arg ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
return ret ;
}
2012-06-19 13:34:04 +04:00
/*******************************************************************
A fcntl wrapper that will deal with EINTR .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_fcntl_long ( int fd , int cmd , long arg )
{
int ret ;
do {
ret = fcntl ( fd , cmd , arg ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
return ret ;
}
2009-05-14 17:34:42 +04:00
/****************************************************************************
Get / Set all the possible time fields from a stat struct as a timespec .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct timespec get_atimespec ( const struct stat * pst )
{
# if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
struct timespec ret ;
/* Old system - no ns timestamp. */
ret . tv_sec = pst - > st_atime ;
ret . tv_nsec = 0 ;
return ret ;
# else
# if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
return pst - > st_atim ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
struct timespec ret ;
ret . tv_sec = pst - > st_atime ;
ret . tv_nsec = pst - > st_atimensec ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
struct timespec ret ;
ret . tv_sec = pst - > st_atime ;
ret . tv_nsec = pst - > st_atime_n ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
struct timespec ret ;
ret . tv_sec = pst - > st_atime ;
ret . tv_nsec = pst - > st_uatime * 1000 ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
return pst - > st_atimespec ;
# else
# error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
# endif
# endif
}
static struct timespec get_mtimespec ( const struct stat * pst )
{
# if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
struct timespec ret ;
/* Old system - no ns timestamp. */
ret . tv_sec = pst - > st_mtime ;
ret . tv_nsec = 0 ;
return ret ;
# else
# if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
return pst - > st_mtim ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
struct timespec ret ;
ret . tv_sec = pst - > st_mtime ;
ret . tv_nsec = pst - > st_mtimensec ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
struct timespec ret ;
ret . tv_sec = pst - > st_mtime ;
ret . tv_nsec = pst - > st_mtime_n ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
struct timespec ret ;
ret . tv_sec = pst - > st_mtime ;
ret . tv_nsec = pst - > st_umtime * 1000 ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
return pst - > st_mtimespec ;
# else
# error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
# endif
# endif
}
static struct timespec get_ctimespec ( const struct stat * pst )
{
# if !defined(HAVE_STAT_HIRES_TIMESTAMPS)
struct timespec ret ;
/* Old system - no ns timestamp. */
ret . tv_sec = pst - > st_ctime ;
ret . tv_nsec = 0 ;
return ret ;
# else
# if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
return pst - > st_ctim ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
struct timespec ret ;
ret . tv_sec = pst - > st_ctime ;
ret . tv_nsec = pst - > st_ctimensec ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
struct timespec ret ;
ret . tv_sec = pst - > st_ctime ;
ret . tv_nsec = pst - > st_ctime_n ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_UMTIME)
struct timespec ret ;
ret . tv_sec = pst - > st_ctime ;
ret . tv_nsec = pst - > st_uctime * 1000 ;
return ret ;
# elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
return pst - > st_ctimespec ;
# else
# error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
# endif
# endif
}
2009-07-08 23:28:01 +04:00
/****************************************************************************
Return the best approximation to a ' create time ' under UNIX from a stat
structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-09 04:51:35 +04:00
static struct timespec calc_create_time_stat ( const struct stat * st )
2009-07-08 23:28:01 +04:00
{
struct timespec ret , ret1 ;
struct timespec c_time = get_ctimespec ( st ) ;
struct timespec m_time = get_mtimespec ( st ) ;
struct timespec a_time = get_atimespec ( st ) ;
ret = timespec_compare ( & c_time , & m_time ) < 0 ? c_time : m_time ;
ret1 = timespec_compare ( & ret , & a_time ) < 0 ? ret : a_time ;
if ( ! null_timespec ( ret1 ) ) {
return ret1 ;
}
/*
* One of ctime , mtime or atime was zero ( probably atime ) .
* Just return MIN ( ctime , mtime ) .
*/
return ret ;
}
2009-07-09 04:51:35 +04:00
/****************************************************************************
Return the best approximation to a ' create time ' under UNIX from a stat_ex
structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct timespec calc_create_time_stat_ex ( const struct stat_ex * st )
{
struct timespec ret , ret1 ;
struct timespec c_time = st - > st_ex_ctime ;
struct timespec m_time = st - > st_ex_mtime ;
struct timespec a_time = st - > st_ex_atime ;
ret = timespec_compare ( & c_time , & m_time ) < 0 ? c_time : m_time ;
ret1 = timespec_compare ( & ret , & a_time ) < 0 ? ret : a_time ;
if ( ! null_timespec ( ret1 ) ) {
return ret1 ;
}
/*
* One of ctime , mtime or atime was zero ( probably atime ) .
* Just return MIN ( ctime , mtime ) .
*/
return ret ;
}
2009-07-08 23:28:01 +04:00
/****************************************************************************
Return the ' create time ' from a stat struct if it exists ( birthtime ) or else
use the best approximation .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-27 14:42:39 +03:00
static void make_create_timespec ( const struct stat * pst , struct stat_ex * dst ,
bool fake_dir_create_times )
2009-07-08 23:28:01 +04:00
{
2009-11-27 14:42:39 +03:00
if ( S_ISDIR ( pst - > st_mode ) & & fake_dir_create_times ) {
2009-07-09 04:51:35 +04:00
dst - > st_ex_btime . tv_sec = 315493200L ; /* 1/1/1980 */
dst - > st_ex_btime . tv_nsec = 0 ;
2009-07-08 23:28:01 +04:00
}
2009-07-09 04:51:35 +04:00
dst - > st_ex_calculated_birthtime = false ;
2009-07-08 23:28:01 +04:00
# if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC)
2009-07-09 04:51:35 +04:00
dst - > st_ex_btime = pst - > st_birthtimespec ;
2009-07-08 23:28:01 +04:00
# elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
2009-07-09 04:51:35 +04:00
dst - > st_ex_btime . tv_sec = pst - > st_birthtime ;
dst - > st_ex_btime . tv_nsec = pst - > st_birthtimenspec ;
2009-07-08 23:28:01 +04:00
# elif defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
2009-07-09 04:51:35 +04:00
dst - > st_ex_btime . tv_sec = pst - > st_birthtime ;
dst - > st_ex_btime . tv_nsec = 0 ;
2009-07-08 23:28:01 +04:00
# else
2009-07-09 04:51:35 +04:00
dst - > st_ex_btime = calc_create_time_stat ( pst ) ;
dst - > st_ex_calculated_birthtime = true ;
2009-07-08 23:28:01 +04:00
# endif
/* Deal with systems that don't initialize birthtime correctly.
* Pointed out by SATOH Fumiyasu < fumiyas @ osstech . jp > .
*/
2009-07-18 05:05:10 +04:00
if ( null_timespec ( dst - > st_ex_btime ) ) {
2009-07-09 04:51:35 +04:00
dst - > st_ex_btime = calc_create_time_stat ( pst ) ;
dst - > st_ex_calculated_birthtime = true ;
2009-07-08 23:28:01 +04:00
}
}
2009-07-09 04:51:35 +04:00
/****************************************************************************
If we update a timestamp in a stat_ex struct we may have to recalculate
the birthtime . For now only implement this for write time , but we may
2009-07-09 05:05:30 +04:00
also need to do it for atime and ctime . JRA .
2009-07-09 04:51:35 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-09 05:05:30 +04:00
void update_stat_ex_mtime ( struct stat_ex * dst ,
2009-07-09 04:51:35 +04:00
struct timespec write_ts )
{
dst - > st_ex_mtime = write_ts ;
/* We may have to recalculate btime. */
if ( dst - > st_ex_calculated_birthtime ) {
dst - > st_ex_btime = calc_create_time_stat_ex ( dst ) ;
}
}
2009-07-08 23:28:01 +04:00
2009-11-18 01:55:02 +03:00
void update_stat_ex_create_time ( struct stat_ex * dst ,
struct timespec create_time )
{
dst - > st_ex_btime = create_time ;
dst - > st_ex_calculated_birthtime = false ;
}
2011-06-03 19:27:13 +04:00
void init_stat_ex_from_stat ( struct stat_ex * dst ,
const struct stat * src ,
bool fake_dir_create_times )
2009-05-14 17:34:42 +04:00
{
dst - > st_ex_dev = src - > st_dev ;
dst - > st_ex_ino = src - > st_ino ;
dst - > st_ex_mode = src - > st_mode ;
dst - > st_ex_nlink = src - > st_nlink ;
dst - > st_ex_uid = src - > st_uid ;
dst - > st_ex_gid = src - > st_gid ;
dst - > st_ex_rdev = src - > st_rdev ;
dst - > st_ex_size = src - > st_size ;
dst - > st_ex_atime = get_atimespec ( src ) ;
dst - > st_ex_mtime = get_mtimespec ( src ) ;
dst - > st_ex_ctime = get_ctimespec ( src ) ;
2009-11-27 14:42:39 +03:00
make_create_timespec ( src , dst , fake_dir_create_times ) ;
2010-06-08 01:06:28 +04:00
# ifdef HAVE_STAT_ST_BLKSIZE
2009-05-14 17:34:42 +04:00
dst - > st_ex_blksize = src - > st_blksize ;
2010-06-08 01:06:28 +04:00
# else
dst - > st_ex_blksize = STAT_ST_BLOCKSIZE ;
# endif
# ifdef HAVE_STAT_ST_BLOCKS
2009-05-14 17:34:42 +04:00
dst - > st_ex_blocks = src - > st_blocks ;
2010-06-08 01:06:28 +04:00
# else
2010-06-09 17:21:24 +04:00
dst - > st_ex_blocks = src - > st_size / dst - > st_ex_blksize + 1 ;
2010-06-08 01:06:28 +04:00
# endif
2009-05-27 00:39:50 +04:00
# ifdef HAVE_STAT_ST_FLAGS
dst - > st_ex_flags = src - > st_flags ;
# else
dst - > st_ex_flags = 0 ;
# endif
2009-05-14 17:34:42 +04:00
}
1998-09-03 22:40:31 +04:00
/*******************************************************************
2012-03-28 02:49:48 +04:00
A stat ( ) wrapper .
1998-09-03 22:40:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-27 14:42:39 +03:00
int sys_stat ( const char * fname , SMB_STRUCT_STAT * sbuf ,
bool fake_dir_create_times )
1998-09-03 22:40:31 +04:00
{
1999-12-13 16:27:58 +03:00
int ret ;
2009-05-14 17:34:42 +04:00
struct stat statbuf ;
ret = stat ( fname , & statbuf ) ;
if ( ret = = 0 ) {
/* we always want directories to appear zero size */
if ( S_ISDIR ( statbuf . st_mode ) ) {
statbuf . st_size = 0 ;
}
2009-11-27 14:42:39 +03:00
init_stat_ex_from_stat ( sbuf , & statbuf , fake_dir_create_times ) ;
2009-05-14 17:34:42 +04:00
}
1999-12-13 16:27:58 +03:00
return ret ;
1998-09-03 22:40:31 +04:00
}
/*******************************************************************
2012-03-28 02:49:48 +04:00
An fstat ( ) wrapper .
1998-09-03 22:40:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-27 14:42:39 +03:00
int sys_fstat ( int fd , SMB_STRUCT_STAT * sbuf , bool fake_dir_create_times )
1998-09-03 22:40:31 +04:00
{
1999-12-13 16:27:58 +03:00
int ret ;
2009-05-14 17:34:42 +04:00
struct stat statbuf ;
ret = fstat ( fd , & statbuf ) ;
if ( ret = = 0 ) {
/* we always want directories to appear zero size */
if ( S_ISDIR ( statbuf . st_mode ) ) {
statbuf . st_size = 0 ;
}
2009-11-27 14:42:39 +03:00
init_stat_ex_from_stat ( sbuf , & statbuf , fake_dir_create_times ) ;
2009-05-14 17:34:42 +04:00
}
1999-12-13 16:27:58 +03:00
return ret ;
1998-09-03 22:40:31 +04:00
}
/*******************************************************************
2012-03-28 02:49:48 +04:00
An lstat ( ) wrapper .
1998-09-03 22:40:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-27 14:42:39 +03:00
int sys_lstat ( const char * fname , SMB_STRUCT_STAT * sbuf ,
bool fake_dir_create_times )
1998-09-03 22:40:31 +04:00
{
1999-12-13 16:27:58 +03:00
int ret ;
2009-05-14 17:34:42 +04:00
struct stat statbuf ;
ret = lstat ( fname , & statbuf ) ;
if ( ret = = 0 ) {
/* we always want directories to appear zero size */
if ( S_ISDIR ( statbuf . st_mode ) ) {
statbuf . st_size = 0 ;
}
2009-11-27 14:42:39 +03:00
init_stat_ex_from_stat ( sbuf , & statbuf , fake_dir_create_times ) ;
2009-05-14 17:34:42 +04:00
}
1999-12-13 16:27:58 +03:00
return ret ;
1998-09-03 22:40:31 +04:00
}
2009-12-02 17:13:37 +03:00
/*******************************************************************
2012-03-28 02:49:48 +04:00
An posix_fallocate ( ) wrapper .
2009-12-02 17:13:37 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-04-05 08:53:08 +04:00
int sys_posix_fallocate ( int fd , off_t offset , off_t len )
2009-12-02 17:13:37 +03:00
{
2012-03-28 02:49:48 +04:00
# if defined(HAVE_POSIX_FALLOCATE) && !defined(HAVE_BROKEN_POSIX_FALLOCATE)
2009-12-02 17:13:37 +03:00
return posix_fallocate ( fd , offset , len ) ;
2010-02-18 12:01:26 +03:00
# elif defined(F_RESVSP64)
/* this handles XFS on IRIX */
struct flock64 fl ;
2012-04-05 08:53:08 +04:00
off_t new_len = offset + len ;
2010-02-18 12:01:26 +03:00
int ret ;
struct stat64 sbuf ;
/* unlikely to get a too large file on a 64bit system but ... */
if ( new_len < 0 )
return EFBIG ;
fl . l_whence = SEEK_SET ;
fl . l_start = offset ;
fl . l_len = len ;
ret = fcntl ( fd , F_RESVSP64 , & fl ) ;
if ( ret ! = 0 )
return errno ;
/* Make sure the file gets enlarged after we allocated space: */
fstat64 ( fd , & sbuf ) ;
if ( new_len > sbuf . st_size )
ftruncate64 ( fd , new_len ) ;
return 0 ;
2009-12-08 23:13:19 +03:00
# else
return ENOSYS ;
2009-12-02 17:13:37 +03:00
# endif
}
2010-12-21 03:53:16 +03:00
/*******************************************************************
An fallocate ( ) function that matches the semantics of the Linux one .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifdef HAVE_LINUX_FALLOC_H
# include <linux/falloc.h>
# endif
2012-04-05 08:53:08 +04:00
int sys_fallocate ( int fd , enum vfs_fallocate_mode mode , off_t offset , off_t len )
2010-12-21 03:53:16 +03:00
{
# if defined(HAVE_LINUX_FALLOCATE64) || defined(HAVE_LINUX_FALLOCATE)
int lmode ;
switch ( mode ) {
case VFS_FALLOCATE_EXTEND_SIZE :
lmode = 0 ;
break ;
case VFS_FALLOCATE_KEEP_SIZE :
lmode = FALLOC_FL_KEEP_SIZE ;
break ;
default :
errno = EINVAL ;
return - 1 ;
}
2012-03-28 02:49:48 +04:00
# if defined(HAVE_LINUX_FALLOCATE)
2010-12-21 03:53:16 +03:00
return fallocate ( fd , lmode , offset , len ) ;
# endif
# else
/* TODO - plumb in fallocate from other filesysetms like VXFS etc. JRA. */
errno = ENOSYS ;
return - 1 ;
# endif
}
2011-05-03 16:45:47 +04:00
# if HAVE_KERNEL_SHARE_MODES
# ifndef LOCK_MAND
# define LOCK_MAND 32 /* This is a mandatory flock */
# define LOCK_READ 64 /* ... Which allows concurrent read operations */
# define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
# define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
# endif
# endif
2006-11-09 23:29:31 +03:00
/*******************************************************************
A flock ( ) wrapper that will perform the kernel flock .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-10-06 19:14:56 +04:00
void kernel_flock ( int fd , uint32 share_mode , uint32 access_mask )
2006-11-09 23:29:31 +03:00
{
# if HAVE_KERNEL_SHARE_MODES
int kernel_mode = 0 ;
if ( share_mode = = FILE_SHARE_WRITE ) {
kernel_mode = LOCK_MAND | LOCK_WRITE ;
} else if ( share_mode = = FILE_SHARE_READ ) {
kernel_mode = LOCK_MAND | LOCK_READ ;
} else if ( share_mode = = FILE_SHARE_NONE ) {
kernel_mode = LOCK_MAND ;
}
if ( kernel_mode ) {
flock ( fd , kernel_mode ) ;
}
# endif
;
}
2011-02-09 01:43:07 +03:00
/*******************************************************************
2012-03-28 02:49:48 +04:00
An fdopendir wrapper .
2011-02-26 04:25:36 +03:00
Ugly hack - we need dirfd for this to work correctly in the
calling code . . JRA .
2011-02-09 01:43:07 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-03-28 06:22:03 +04:00
DIR * sys_fdopendir ( int fd )
2011-02-09 01:43:07 +03:00
{
2012-03-28 02:49:48 +04:00
# if defined(HAVE_FDOPENDIR) && defined(HAVE_DIRFD)
2011-02-09 01:43:07 +03:00
return fdopendir ( fd ) ;
# else
errno = ENOSYS ;
return NULL ;
# endif
}
2004-11-10 01:49:28 +03:00
/*******************************************************************
2012-03-28 02:49:48 +04:00
An mknod ( ) wrapper .
2002-01-10 03:28:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_mknod ( const char * path , mode_t mode , SMB_DEV_T dev )
{
2012-03-28 02:49:48 +04:00
# if defined(HAVE_MKNOD)
2002-01-10 03:28:09 +03:00
return mknod ( path , mode , dev ) ;
1999-12-13 16:27:58 +03:00
# else
2002-01-10 03:28:09 +03:00
/* No mknod system call. */
errno = ENOSYS ;
return - 1 ;
1999-12-13 16:27:58 +03:00
# endif
}
1996-10-05 06:54:37 +04:00
/*******************************************************************
The wait ( ) calls vary between systems
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-11-26 00:17:20 +03:00
1996-10-05 06:54:37 +04:00
int sys_waitpid ( pid_t pid , int * status , int options )
{
1998-07-29 07:08:05 +04:00
# ifdef HAVE_WAITPID
2002-01-10 03:28:09 +03:00
return waitpid ( pid , status , options ) ;
1998-07-29 07:08:05 +04:00
# else /* HAVE_WAITPID */
2002-01-10 03:28:09 +03:00
return wait4 ( pid , status , options , NULL ) ;
1998-07-29 07:08:05 +04:00
# endif /* HAVE_WAITPID */
1996-10-05 06:54:37 +04:00
}
1997-08-22 00:03:45 +04:00
/*******************************************************************
2011-06-01 03:14:04 +04:00
System wrapper for getwd . Always returns MALLOC ' ed memory , or NULL
on error ( malloc fail usually ) .
1997-08-22 00:03:45 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-10 03:28:09 +03:00
2011-06-01 03:14:04 +04:00
char * sys_getwd ( void )
1997-08-22 00:03:45 +04:00
{
2011-06-01 03:14:04 +04:00
# ifdef GETCWD_TAKES_NULL
return getcwd ( NULL , 0 ) ;
# elif HAVE_GETCWD
char * wd = NULL , * s = NULL ;
size_t allocated = PATH_MAX ;
while ( 1 ) {
s = SMB_REALLOC_ARRAY ( s , char , allocated ) ;
if ( s = = NULL ) {
return NULL ;
}
wd = getcwd ( s , allocated ) ;
if ( wd ) {
break ;
}
if ( errno ! = ERANGE ) {
SAFE_FREE ( s ) ;
break ;
}
allocated * = 2 ;
if ( allocated < PATH_MAX ) {
SAFE_FREE ( s ) ;
break ;
}
}
return wd ;
1997-08-22 00:03:45 +04:00
# else
2011-06-01 03:14:04 +04:00
char * s = SMB_MALLOC_ARRAY ( char , PATH_MAX ) ;
if ( s = = NULL ) {
return NULL ;
}
return getwd ( s ) ;
1997-08-22 00:03:45 +04:00
# endif
1998-10-02 16:35:28 +04:00
}
2006-03-21 05:56:49 +03:00
# if defined(HAVE_POSIX_CAPABILITIES)
1998-09-26 03:40:49 +04:00
/**************************************************************************
2006-03-21 05:56:49 +03:00
Try and abstract process capabilities ( for systems that have them ) .
1998-09-26 03:40:49 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-03-21 05:56:49 +03:00
/* Set the POSIX capabilities needed for the given purpose into the effective
* capability set of the current process . Make sure they are always removed
* from the inheritable set , because there is no circumstance in which our
* children should inherit our elevated privileges .
*/
2007-10-19 04:40:25 +04:00
static bool set_process_capability ( enum smbd_capability capability ,
bool enable )
1998-09-26 03:40:49 +04:00
{
2006-03-21 05:56:49 +03:00
cap_value_t cap_vals [ 2 ] = { 0 } ;
int num_cap_vals = 0 ;
1998-09-26 03:40:49 +04:00
2006-03-21 05:56:49 +03:00
cap_t cap ;
1998-09-26 03:40:49 +04:00
2006-03-23 02:49:09 +03:00
# if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
/* On Linux, make sure that any capabilities we grab are sticky
* across UID changes . We expect that this would allow us to keep both
* the effective and permitted capability sets , but as of circa 2.6 .16 ,
* only the permitted set is kept . It is a bug ( which we work around )
* that the effective set is lost , but we still require the effective
* set to be kept .
*/
if ( ! prctl ( PR_GET_KEEPCAPS ) ) {
prctl ( PR_SET_KEEPCAPS , 1 ) ;
}
# endif
2006-03-21 05:56:49 +03:00
cap = cap_get_proc ( ) ;
if ( cap = = NULL ) {
DEBUG ( 0 , ( " set_process_capability: cap_get_proc failed: %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
1998-09-26 03:40:49 +04:00
2006-03-21 05:56:49 +03:00
switch ( capability ) {
case KERNEL_OPLOCK_CAPABILITY :
# ifdef CAP_NETWORK_MGT
/* IRIX has CAP_NETWORK_MGT for oplocks. */
cap_vals [ num_cap_vals + + ] = CAP_NETWORK_MGT ;
2006-03-23 02:49:09 +03:00
# endif
break ;
case DMAPI_ACCESS_CAPABILITY :
# ifdef CAP_DEVICE_MGT
/* IRIX has CAP_DEVICE_MGT for DMAPI access. */
cap_vals [ num_cap_vals + + ] = CAP_DEVICE_MGT ;
# elif CAP_MKNOD
/* Linux has CAP_MKNOD for DMAPI access. */
cap_vals [ num_cap_vals + + ] = CAP_MKNOD ;
2008-05-28 15:20:16 +04:00
# endif
break ;
case LEASE_CAPABILITY :
# ifdef CAP_LEASE
cap_vals [ num_cap_vals + + ] = CAP_LEASE ;
2006-03-21 05:56:49 +03:00
# endif
break ;
}
SMB_ASSERT ( num_cap_vals < = ARRAY_SIZE ( cap_vals ) ) ;
1998-09-26 03:40:49 +04:00
2006-03-21 05:56:49 +03:00
if ( num_cap_vals = = 0 ) {
2002-01-10 03:28:09 +03:00
cap_free ( cap ) ;
2006-03-21 05:56:49 +03:00
return True ;
}
1999-12-13 16:27:58 +03:00
2010-03-08 22:34:39 +03:00
cap_set_flag ( cap , CAP_EFFECTIVE , num_cap_vals , cap_vals ,
enable ? CAP_SET : CAP_CLEAR ) ;
2006-03-23 02:49:09 +03:00
/* We never want to pass capabilities down to our children, so make
* sure they are not inherited .
*/
2010-03-08 22:34:39 +03:00
cap_set_flag ( cap , CAP_INHERITABLE , num_cap_vals , cap_vals , CAP_CLEAR ) ;
2006-03-21 05:56:49 +03:00
if ( cap_set_proc ( cap ) = = - 1 ) {
2010-03-08 22:34:39 +03:00
DEBUG ( 0 , ( " set_process_capability: cap_set_proc failed: %s \n " ,
2006-03-21 05:56:49 +03:00
strerror ( errno ) ) ) ;
cap_free ( cap ) ;
return False ;
2002-01-10 03:28:09 +03:00
}
2006-03-21 05:56:49 +03:00
cap_free ( cap ) ;
2002-01-10 03:28:09 +03:00
return True ;
1998-09-26 03:40:49 +04:00
}
2006-03-21 05:56:49 +03:00
# endif /* HAVE_POSIX_CAPABILITIES */
2000-06-09 10:58:06 +04:00
/****************************************************************************
2002-01-10 03:28:09 +03:00
Gain the oplock capability from the kernel if possible .
2000-06-09 10:58:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-10 03:28:09 +03:00
2006-03-21 05:56:49 +03:00
void set_effective_capability ( enum smbd_capability capability )
2000-06-09 10:58:06 +04:00
{
2006-03-21 05:56:49 +03:00
# if defined(HAVE_POSIX_CAPABILITIES)
set_process_capability ( capability , True ) ;
# endif /* HAVE_POSIX_CAPABILITIES */
}
void drop_effective_capability ( enum smbd_capability capability )
{
# if defined(HAVE_POSIX_CAPABILITIES)
set_process_capability ( capability , False ) ;
# endif /* HAVE_POSIX_CAPABILITIES */
2000-06-09 10:58:06 +04:00
}
1998-09-26 03:40:49 +04:00
/**************************************************************************
Wrapper for random ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
long sys_random ( void )
{
# if defined(HAVE_RANDOM)
2002-01-10 03:28:09 +03:00
return ( long ) random ( ) ;
1998-09-26 03:40:49 +04:00
# elif defined(HAVE_RAND)
2002-01-10 03:28:09 +03:00
return ( long ) rand ( ) ;
1998-09-26 03:40:49 +04:00
# else
2002-01-10 03:28:09 +03:00
DEBUG ( 0 , ( " Error - no random function available ! \n " ) ) ;
exit ( 1 ) ;
1998-09-26 03:40:49 +04:00
# endif
}
/**************************************************************************
Wrapper for srandom ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void sys_srandom ( unsigned int seed )
{
# if defined(HAVE_SRANDOM)
2002-01-10 03:28:09 +03:00
srandom ( seed ) ;
1998-09-26 03:40:49 +04:00
# elif defined(HAVE_SRAND)
2002-01-10 03:28:09 +03:00
srand ( seed ) ;
1998-09-26 03:40:49 +04:00
# else
2002-01-10 03:28:09 +03:00
DEBUG ( 0 , ( " Error - no srandom function available ! \n " ) ) ;
exit ( 1 ) ;
1998-09-26 03:40:49 +04:00
# endif
}
1998-09-30 00:24:17 +04:00
2011-02-12 04:51:19 +03:00
# ifndef NGROUPS_MAX
# define NGROUPS_MAX 32 /* Guess... */
# endif
2000-02-15 22:36:47 +03:00
/**************************************************************************
Returns equivalent to NGROUPS_MAX - using sysconf if needed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int groups_max ( void )
{
# if defined(SYSCONF_SC_NGROUPS_MAX)
2002-01-10 03:28:09 +03:00
int ret = sysconf ( _SC_NGROUPS_MAX ) ;
return ( ret = = - 1 ) ? NGROUPS_MAX : ret ;
2000-02-15 22:36:47 +03:00
# else
2002-01-10 03:28:09 +03:00
return NGROUPS_MAX ;
2000-02-15 22:36:47 +03:00
# endif
}
1998-09-30 00:24:17 +04:00
/**************************************************************************
2007-06-09 02:25:55 +04:00
Wrap setgroups and getgroups for systems that declare getgroups ( ) as
returning an array of gid_t , but actuall return an array of int .
1998-09-30 00:24:17 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-06-09 02:25:55 +04:00
# if defined(HAVE_BROKEN_GETGROUPS)
2011-02-12 04:51:19 +03:00
# ifdef HAVE_BROKEN_GETGROUPS
# define GID_T int
# else
# define GID_T gid_t
# endif
2007-06-09 02:25:55 +04:00
static int sys_broken_getgroups ( int setlen , gid_t * gidset )
1998-09-30 00:24:17 +04:00
{
2002-01-10 03:28:09 +03:00
GID_T gid ;
GID_T * group_list ;
int i , ngroups ;
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
if ( setlen = = 0 ) {
return getgroups ( setlen , & gid ) ;
}
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
/*
* Broken case . We need to allocate a
* GID_T array of size setlen .
*/
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
if ( setlen < 0 ) {
errno = EINVAL ;
return - 1 ;
}
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
if ( setlen = = 0 )
setlen = groups_max ( ) ;
1998-10-05 12:42:41 +04:00
2007-06-09 02:25:55 +04:00
if ( ( group_list = SMB_MALLOC_ARRAY ( GID_T , setlen ) ) = = NULL ) {
2002-01-10 03:28:09 +03:00
DEBUG ( 0 , ( " sys_getgroups: Malloc fail. \n " ) ) ;
return - 1 ;
}
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
if ( ( ngroups = getgroups ( setlen , group_list ) ) < 0 ) {
int saved_errno = errno ;
SAFE_FREE ( group_list ) ;
errno = saved_errno ;
return - 1 ;
}
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
for ( i = 0 ; i < ngroups ; i + + )
gidset [ i ] = ( gid_t ) group_list [ i ] ;
1998-09-30 00:24:17 +04:00
2002-01-10 03:28:09 +03:00
SAFE_FREE ( group_list ) ;
return ngroups ;
1998-09-30 00:24:17 +04:00
}
1999-07-07 01:50:29 +04:00
2007-06-14 01:42:31 +04:00
static int sys_broken_setgroups ( int setlen , gid_t * gidset )
1999-12-13 16:27:58 +03:00
{
2002-01-10 03:28:09 +03:00
GID_T * group_list ;
int i ;
1999-12-13 16:27:58 +03:00
2002-01-10 03:28:09 +03:00
if ( setlen = = 0 )
return 0 ;
1999-12-13 16:27:58 +03:00
2002-01-10 03:28:09 +03:00
if ( setlen < 0 | | setlen > groups_max ( ) ) {
errno = EINVAL ;
return - 1 ;
}
1999-12-13 16:27:58 +03:00
2002-01-10 03:28:09 +03:00
/*
* Broken case . We need to allocate a
* GID_T array of size setlen .
*/
1999-12-13 16:27:58 +03:00
2007-06-09 02:25:55 +04:00
if ( ( group_list = SMB_MALLOC_ARRAY ( GID_T , setlen ) ) = = NULL ) {
2002-01-10 03:28:09 +03:00
DEBUG ( 0 , ( " sys_setgroups: Malloc fail. \n " ) ) ;
return - 1 ;
}
2009-05-14 14:13:24 +04:00
2002-01-10 03:28:09 +03:00
for ( i = 0 ; i < setlen ; i + + )
group_list [ i ] = ( GID_T ) gidset [ i ] ;
2012-06-28 22:59:51 +04:00
if ( samba_setgroups ( setlen , group_list ) ! = 0 ) {
2002-01-10 03:28:09 +03:00
int saved_errno = errno ;
SAFE_FREE ( group_list ) ;
errno = saved_errno ;
return - 1 ;
}
2009-05-14 14:13:24 +04:00
2002-01-10 03:28:09 +03:00
SAFE_FREE ( group_list ) ;
return 0 ;
2007-06-09 02:25:55 +04:00
}
1999-12-13 16:27:58 +03:00
# endif /* HAVE_BROKEN_GETGROUPS */
2007-06-09 02:25:55 +04:00
/* This is a list of systems that require the first GID passed to setgroups(2)
* to be the effective GID . If your system is one of these , add it here .
*/
# if defined (FREEBSD) || defined (DARWINOS)
# define USE_BSD_SETGROUPS
# endif
# if defined(USE_BSD_SETGROUPS)
/* Depending on the particular BSD implementation, the first GID that is
* passed to setgroups ( 2 ) will either be ignored or will set the credential ' s
* effective GID . In either case , the right thing to do is to guarantee that
* gidset [ 0 ] is the effective GID .
*/
static int sys_bsd_setgroups ( gid_t primary_gid , int setlen , const gid_t * gidset )
{
gid_t * new_gidset = NULL ;
int max ;
int ret ;
/* setgroups(2) will fail with EINVAL if we pass too many groups. */
max = groups_max ( ) ;
/* No group list, just make sure we are setting the efective GID. */
if ( setlen = = 0 ) {
2012-06-28 22:59:51 +04:00
return samba_setgroups ( 1 , & primary_gid ) ;
2007-06-09 02:25:55 +04:00
}
/* If the primary gid is not the first array element, grow the array
* and insert it at the front .
*/
if ( gidset [ 0 ] ! = primary_gid ) {
new_gidset = SMB_MALLOC_ARRAY ( gid_t , setlen + 1 ) ;
if ( new_gidset = = NULL ) {
return - 1 ;
}
2007-06-21 18:23:06 +04:00
memcpy ( new_gidset + 1 , gidset , ( setlen * sizeof ( gid_t ) ) ) ;
2007-06-09 02:25:55 +04:00
new_gidset [ 0 ] = primary_gid ;
setlen + + ;
}
2007-06-14 00:40:50 +04:00
if ( setlen > max ) {
2007-06-14 01:42:31 +04:00
DEBUG ( 3 , ( " forced to truncate group list from %d to %d \n " ,
2007-06-14 00:40:50 +04:00
setlen , max ) ) ;
setlen = max ;
}
2007-06-22 01:17:06 +04:00
# if defined(HAVE_BROKEN_GETGROUPS)
2007-06-14 00:40:50 +04:00
ret = sys_broken_setgroups ( setlen , new_gidset ? new_gidset : gidset ) ;
2007-06-09 02:25:55 +04:00
# else
2012-06-28 22:59:51 +04:00
ret = samba_setgroups ( setlen , new_gidset ? new_gidset : gidset ) ;
2007-06-09 02:25:55 +04:00
# endif
if ( new_gidset ) {
int errsav = errno ;
SAFE_FREE ( new_gidset ) ;
errno = errsav ;
}
return ret ;
}
# endif /* USE_BSD_SETGROUPS */
/**************************************************************************
Wrapper for getgroups . Deals with broken ( int ) case .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_getgroups ( int setlen , gid_t * gidset )
{
# if defined(HAVE_BROKEN_GETGROUPS)
return sys_broken_getgroups ( setlen , gidset ) ;
# else
return getgroups ( setlen , gidset ) ;
# endif
}
/**************************************************************************
Wrapper for setgroups . Deals with broken ( int ) case and BSD case .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_setgroups ( gid_t UNUSED ( primary_gid ) , int setlen , gid_t * gidset )
{
# if !defined(HAVE_SETGROUPS)
errno = ENOSYS ;
return - 1 ;
# endif /* HAVE_SETGROUPS */
2007-06-22 01:17:06 +04:00
# if defined(USE_BSD_SETGROUPS)
2007-06-09 02:25:55 +04:00
return sys_bsd_setgroups ( primary_gid , setlen , gidset ) ;
2007-06-22 01:17:06 +04:00
# elif defined(HAVE_BROKEN_GETGROUPS)
return sys_broken_setgroups ( setlen , gidset ) ;
2007-06-09 02:25:55 +04:00
# else
2012-06-28 22:59:51 +04:00
return samba_setgroups ( setlen , gidset ) ;
2007-06-09 02:25:55 +04:00
# endif
1999-12-13 16:27:58 +03:00
}
2000-02-15 22:36:47 +03:00
/**************************************************************************
2007-06-29 20:04:26 +04:00
Extract a command into an arg list .
2000-02-15 22:36:47 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-06-29 20:04:26 +04:00
static char * * extract_args ( TALLOC_CTX * mem_ctx , const char * command )
2000-02-15 22:36:47 +03:00
{
2007-06-29 20:04:26 +04:00
char * trunc_cmd ;
char * saveptr ;
2000-02-15 22:36:47 +03:00
char * ptr ;
int argcl ;
char * * argl = NULL ;
int i ;
2007-06-29 20:04:26 +04:00
if ( ! ( trunc_cmd = talloc_strdup ( mem_ctx , command ) ) ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
goto nomem ;
}
2000-02-15 22:36:47 +03:00
2007-06-29 20:04:26 +04:00
if ( ! ( ptr = strtok_r ( trunc_cmd , " \t " , & saveptr ) ) ) {
TALLOC_FREE ( trunc_cmd ) ;
2000-02-15 22:36:47 +03:00
errno = EINVAL ;
return NULL ;
}
/*
* Count the args .
*/
2007-06-29 20:04:26 +04:00
for ( argcl = 1 ; ptr ; ptr = strtok_r ( NULL , " \t " , & saveptr ) )
2000-02-15 22:36:47 +03:00
argcl + + ;
2007-06-29 20:04:26 +04:00
TALLOC_FREE ( trunc_cmd ) ;
2011-06-07 05:30:12 +04:00
if ( ! ( argl = talloc_array ( mem_ctx , char * , argcl + 1 ) ) ) {
2007-06-29 20:04:26 +04:00
goto nomem ;
}
2000-02-15 22:36:47 +03:00
/*
* Now do the extraction .
*/
2007-06-29 20:04:26 +04:00
if ( ! ( trunc_cmd = talloc_strdup ( mem_ctx , command ) ) ) {
goto nomem ;
}
2000-02-15 22:36:47 +03:00
2007-06-29 20:04:26 +04:00
ptr = strtok_r ( trunc_cmd , " \t " , & saveptr ) ;
2000-02-15 22:36:47 +03:00
i = 0 ;
2007-06-29 20:04:26 +04:00
if ( ! ( argl [ i + + ] = talloc_strdup ( argl , ptr ) ) ) {
goto nomem ;
}
while ( ( ptr = strtok_r ( NULL , " \t " , & saveptr ) ) ! = NULL ) {
if ( ! ( argl [ i + + ] = talloc_strdup ( argl , ptr ) ) ) {
goto nomem ;
}
}
2000-02-15 22:36:47 +03:00
argl [ i + + ] = NULL ;
2009-11-14 19:23:08 +03:00
TALLOC_FREE ( trunc_cmd ) ;
2000-02-15 22:36:47 +03:00
return argl ;
2007-06-29 20:04:26 +04:00
nomem :
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( trunc_cmd ) ;
TALLOC_FREE ( argl ) ;
errno = ENOMEM ;
return NULL ;
2000-02-15 22:36:47 +03:00
}
/**************************************************************************
Wrapper for popen . Safer as it doesn ' t search a path .
Modified from the glibc sources .
2000-04-16 15:00:21 +04:00
modified by tridge to return a file descriptor . We must kick our FILE * habit
2000-02-15 22:36:47 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-05-02 06:23:41 +04:00
2000-02-15 22:36:47 +03:00
typedef struct _popen_list
{
2000-04-16 15:00:21 +04:00
int fd ;
2000-02-15 22:36:47 +03:00
pid_t child_pid ;
struct _popen_list * next ;
} popen_list ;
static popen_list * popen_chain ;
2000-04-16 15:00:21 +04:00
int sys_popen ( const char * command )
2000-02-15 22:36:47 +03:00
{
int parent_end , child_end ;
int pipe_fds [ 2 ] ;
2000-04-16 15:00:21 +04:00
popen_list * entry = NULL ;
2000-02-15 22:36:47 +03:00
char * * argl = NULL ;
2012-08-01 17:42:49 +04:00
int ret ;
2000-02-15 22:36:47 +03:00
2012-09-04 17:15:42 +04:00
if ( ! * command ) {
errno = EINVAL ;
return - 1 ;
}
2012-09-04 17:17:37 +04:00
ret = pipe ( pipe_fds ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " sys_popen: error opening pipe: %s \n " ,
strerror ( errno ) ) ) ;
2000-04-16 15:00:21 +04:00
return - 1 ;
2012-09-04 17:17:37 +04:00
}
2000-02-15 22:36:47 +03:00
2000-04-16 15:00:21 +04:00
parent_end = pipe_fds [ 0 ] ;
child_end = pipe_fds [ 1 ] ;
2000-02-15 22:36:47 +03:00
2012-09-04 17:19:46 +04:00
entry = SMB_MALLOC_P ( popen_list ) ;
if ( entry = = NULL ) {
DEBUG ( 0 , ( " sys_popen: malloc failed \n " ) ) ;
2000-02-15 22:36:47 +03:00
goto err_exit ;
2012-09-04 17:19:46 +04:00
}
2000-02-15 22:36:47 +03:00
2000-10-09 01:21:27 +04:00
ZERO_STRUCTP ( entry ) ;
2000-02-15 22:36:47 +03:00
/*
* Extract the command and args into a NULL terminated array .
*/
2012-09-04 17:23:01 +04:00
argl = extract_args ( NULL , command ) ;
if ( argl = = NULL ) {
2012-09-04 17:24:46 +04:00
DEBUG ( 0 , ( " sys_popen: extract_args() failed: %s \n " , strerror ( errno ) ) ) ;
2000-02-15 22:36:47 +03:00
goto err_exit ;
2012-09-04 17:23:01 +04:00
}
2000-02-15 22:36:47 +03:00
2012-03-24 23:17:08 +04:00
entry - > child_pid = fork ( ) ;
2000-02-15 22:36:47 +03:00
if ( entry - > child_pid = = - 1 ) {
goto err_exit ;
}
if ( entry - > child_pid = = 0 ) {
/*
* Child !
*/
2000-04-16 15:00:21 +04:00
int child_std_end = STDOUT_FILENO ;
2000-02-15 22:36:47 +03:00
popen_list * p ;
close ( parent_end ) ;
if ( child_end ! = child_std_end ) {
dup2 ( child_end , child_std_end ) ;
close ( child_end ) ;
}
/*
* POSIX .2 : " popen() shall ensure that any streams from previous
* popen ( ) calls that remain open in the parent process are closed
* in the new child process . "
*/
for ( p = popen_chain ; p ; p = p - > next )
2000-04-16 15:00:21 +04:00
close ( p - > fd ) ;
2000-02-15 22:36:47 +03:00
2012-08-01 17:42:49 +04:00
ret = execv ( argl [ 0 ] , argl ) ;
if ( ret = = - 1 ) {
2012-09-04 16:21:37 +04:00
DEBUG ( 0 , ( " sys_popen: ERROR executing command "
2012-08-01 17:42:49 +04:00
" '%s': %s \n " , command , strerror ( errno ) ) ) ;
}
2000-02-15 22:36:47 +03:00
_exit ( 127 ) ;
}
/*
* Parent .
*/
close ( child_end ) ;
2007-06-29 20:04:26 +04:00
TALLOC_FREE ( argl ) ;
2000-02-15 22:36:47 +03:00
/* Link into popen_chain. */
entry - > next = popen_chain ;
popen_chain = entry ;
2000-10-09 01:21:27 +04:00
entry - > fd = parent_end ;
2000-02-15 22:36:47 +03:00
2000-04-16 15:00:21 +04:00
return entry - > fd ;
2000-02-15 22:36:47 +03:00
err_exit :
2001-09-17 06:19:44 +04:00
SAFE_FREE ( entry ) ;
2011-02-10 20:01:46 +03:00
TALLOC_FREE ( argl ) ;
2000-02-15 22:36:47 +03:00
close ( pipe_fds [ 0 ] ) ;
close ( pipe_fds [ 1 ] ) ;
2000-04-16 15:00:21 +04:00
return - 1 ;
2000-02-15 22:36:47 +03:00
}
/**************************************************************************
Wrapper for pclose . Modified from the glibc sources .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-10 03:28:09 +03:00
2000-04-16 15:00:21 +04:00
int sys_pclose ( int fd )
2000-02-15 22:36:47 +03:00
{
int wstatus ;
popen_list * * ptr = & popen_chain ;
popen_list * entry = NULL ;
pid_t wait_pid ;
int status = - 1 ;
/* Unlink from popen_chain. */
for ( ; * ptr ! = NULL ; ptr = & ( * ptr ) - > next ) {
2000-04-16 15:00:21 +04:00
if ( ( * ptr ) - > fd = = fd ) {
2000-02-15 22:36:47 +03:00
entry = * ptr ;
* ptr = ( * ptr ) - > next ;
status = 0 ;
break ;
}
}
2000-04-16 15:00:21 +04:00
if ( status < 0 | | close ( entry - > fd ) < 0 )
2000-02-15 22:36:47 +03:00
return - 1 ;
/*
* As Samba is catching and eating child process
* exits we don ' t really care about the child exit
* code , a - 1 with errno = ECHILD will do fine for us .
*/
do {
wait_pid = sys_waitpid ( entry - > child_pid , & wstatus , 0 ) ;
} while ( wait_pid = = - 1 & & errno = = EINTR ) ;
2001-09-17 06:19:44 +04:00
SAFE_FREE ( entry ) ;
2000-02-15 22:36:47 +03:00
if ( wait_pid = = - 1 )
return - 1 ;
return wstatus ;
}
2001-03-19 10:08:02 +03:00
2002-03-28 02:17:50 +03:00
/**************************************************************************
Wrapper for Admin Logs .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-01-03 06:24:23 +03:00
void sys_adminlog ( int priority , const char * format_str , . . . )
2002-03-28 02:17:50 +03:00
{
va_list ap ;
int ret ;
2002-09-25 19:19:00 +04:00
char * msgbuf = NULL ;
2002-03-28 02:17:50 +03:00
va_start ( ap , format_str ) ;
2002-09-25 19:19:00 +04:00
ret = vasprintf ( & msgbuf , format_str , ap ) ;
2002-03-28 02:17:50 +03:00
va_end ( ap ) ;
if ( ret = = - 1 )
return ;
# if defined(HAVE_SYSLOG)
2002-09-25 19:19:00 +04:00
syslog ( priority , " %s " , msgbuf ) ;
2002-03-28 02:17:50 +03:00
# else
2002-09-25 19:19:00 +04:00
DEBUG ( 0 , ( " %s " , msgbuf ) ) ;
2002-03-28 02:17:50 +03:00
# endif
2002-09-25 19:19:00 +04:00
SAFE_FREE ( msgbuf ) ;
2002-03-28 02:17:50 +03:00
}
2003-06-06 00:29:55 +04:00
2004-09-26 10:27:54 +04:00
/****************************************************************************
Return the major devicenumber for UNIX extensions .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-14 14:13:24 +04:00
2004-09-26 10:27:54 +04:00
uint32 unix_dev_major ( SMB_DEV_T dev )
{
# if defined(HAVE_DEVICE_MAJOR_FN)
return ( uint32 ) major ( dev ) ;
# else
return ( uint32 ) ( dev > > 8 ) ;
# endif
}
2009-05-14 14:13:24 +04:00
2004-09-26 10:27:54 +04:00
/****************************************************************************
Return the minor devicenumber for UNIX extensions .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-14 14:13:24 +04:00
2004-09-26 10:27:54 +04:00
uint32 unix_dev_minor ( SMB_DEV_T dev )
{
# if defined(HAVE_DEVICE_MINOR_FN)
return ( uint32 ) minor ( dev ) ;
# else
return ( uint32 ) ( dev & 0xff ) ;
# endif
}
2005-06-28 02:53:56 +04:00
2012-01-07 02:55:30 +04:00
#if 0
2012-01-06 03:48:24 +04:00
/*******************************************************************
Return the number of CPUs .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sys_get_number_of_cores ( void )
{
int ret = - 1 ;
# if defined(HAVE_SYSCONF)
# if defined(_SC_NPROCESSORS_ONLN)
ret = ( int ) sysconf ( _SC_NPROCESSORS_ONLN ) ;
# endif
# if defined(_SC_NPROCESSORS_CONF)
if ( ret < 1 ) {
ret = ( int ) sysconf ( _SC_NPROCESSORS_CONF ) ;
}
# endif
# elif defined(HAVE_SYSCTL) && defined(CTL_HW)
int name [ 2 ] ;
unsigned int len = sizeof ( ret ) ;
name [ 0 ] = CTL_HW ;
# if defined(HW_AVAILCPU)
name [ 1 ] = HW_AVAILCPU ;
if ( sysctl ( name , 2 , & ret , & len , NULL , 0 ) = = - 1 ) {
ret = - 1 ;
}
# endif
# if defined(HW_NCPU)
if ( ret < 1 ) {
name [ 0 ] = CTL_HW ;
name [ 1 ] = HW_NCPU ;
if ( sysctl ( nm , 2 , & count , & len , NULL , 0 ) = = - 1 ) {
ret = - 1 ;
}
}
# endif
# endif
if ( ret < 1 ) {
ret = 1 ;
}
return ret ;
}
2012-01-07 02:55:30 +04:00
# endif