2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
Samba utility functions
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Jeremy Allison 2001 - 2002
2011-04-21 18:04:06 +04:00
Copyright ( C ) Simo Sorce 2001 - 2011
2004-07-28 17:08:08 +04:00
Copyright ( C ) Jim McDonough ( jmcd @ us . ibm . com ) 2003.
2003-08-13 05:53:07 +04:00
Copyright ( C ) James J Myers 2003
2011-04-21 17:45:27 +04:00
Copyright ( C ) Volker Lendecke 2010
2003-08-13 05:53:07 +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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04: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 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2004-11-02 01:48:25 +03:00
# include "system/network.h"
2005-02-10 08:09:35 +03:00
# include "system/filesys.h"
2006-05-13 23:14:12 +04:00
# include "system/locale.h"
2010-03-22 10:27:58 +03:00
# include "system/shmem.h"
2011-10-27 14:00:53 +04:00
# include "system/passwd.h"
2010-03-22 10:27:58 +03:00
2008-10-17 14:26:46 +04:00
# undef malloc
# undef strcasecmp
2008-10-19 14:38:16 +04:00
# undef strncasecmp
2008-10-17 14:26:46 +04:00
# undef strdup
# undef realloc
2012-03-24 20:16:26 +04:00
# undef calloc
2003-08-13 05:53:07 +04:00
2006-02-28 16:12:39 +03:00
/**
* @ file
* @ brief Misc utility functions
*/
/**
2003-08-13 05:53:07 +04:00
Find a suitable temporary directory . The result should be copied immediately
as it may be overwritten by a subsequent call .
2006-02-28 16:12:39 +03:00
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ const char * tmpdir ( void )
2003-08-13 05:53:07 +04:00
{
char * p ;
if ( ( p = getenv ( " TMPDIR " ) ) )
return p ;
return " /tmp " ;
}
2011-04-21 17:45:27 +04:00
/**
Create a tmp file , open it and immediately unlink it .
2011-04-21 18:04:06 +04:00
If dir is NULL uses tmpdir ( )
2011-04-21 17:45:27 +04:00
Returns the file descriptor or - 1 on error .
* */
int create_unlink_tmp ( const char * dir )
{
char * fname ;
int fd ;
2011-04-21 18:04:06 +04:00
if ( ! dir ) {
dir = tmpdir ( ) ;
}
2011-04-21 17:45:27 +04:00
fname = talloc_asprintf ( talloc_tos ( ) , " %s/listenerlock_XXXXXX " , dir ) ;
if ( fname = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
fd = mkstemp ( fname ) ;
if ( fd = = - 1 ) {
TALLOC_FREE ( fname ) ;
return - 1 ;
}
if ( unlink ( fname ) = = - 1 ) {
int sys_errno = errno ;
close ( fd ) ;
TALLOC_FREE ( fname ) ;
errno = sys_errno ;
return - 1 ;
}
TALLOC_FREE ( fname ) ;
return fd ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check if a file exists - call vfs_file_exist for samba files .
2006-02-28 16:12:39 +03:00
* */
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool file_exist ( const char * fname )
2003-08-13 05:53:07 +04:00
{
2004-11-01 23:21:54 +03:00
struct stat st ;
2003-08-13 05:53:07 +04:00
2005-02-10 09:36:30 +03:00
if ( stat ( fname , & st ) ! = 0 ) {
2007-08-27 21:21:16 +04:00
return false ;
2005-02-10 09:36:30 +03:00
}
return ( ( S_ISREG ( st . st_mode ) ) | | ( S_ISFIFO ( st . st_mode ) ) ) ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check a files mod time .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-03-05 20:15:19 +03:00
_PUBLIC_ time_t file_modtime ( const char * fname )
2003-08-13 05:53:07 +04:00
{
2004-11-01 23:21:54 +03:00
struct stat st ;
2003-08-13 05:53:07 +04:00
2004-11-01 23:21:54 +03:00
if ( stat ( fname , & st ) ! = 0 )
2003-08-13 05:53:07 +04:00
return ( 0 ) ;
return ( st . st_mtime ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check if a directory exists .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool directory_exist ( const char * dname )
2003-08-13 05:53:07 +04:00
{
2005-02-10 09:36:30 +03:00
struct stat st ;
2007-08-27 21:21:16 +04:00
bool ret ;
2003-08-13 05:53:07 +04:00
2005-02-10 09:36:30 +03:00
if ( stat ( dname , & st ) ! = 0 ) {
2007-08-27 21:21:16 +04:00
return false ;
2005-02-10 09:36:30 +03:00
}
2003-08-13 05:53:07 +04:00
2005-02-10 09:36:30 +03:00
ret = S_ISDIR ( st . st_mode ) ;
2003-08-13 05:53:07 +04:00
if ( ! ret )
errno = ENOTDIR ;
return ret ;
}
2006-03-06 03:24:51 +03:00
/**
* Try to create the specified directory if it didn ' t exist .
*
2007-08-27 21:21:16 +04:00
* @ retval true if the directory already existed and has the right permissions
2006-03-06 03:24:51 +03:00
* or was successfully created .
*/
2013-01-08 17:21:00 +04:00
_PUBLIC_ bool directory_create_or_exist ( const char * dname ,
uid_t uid ,
mode_t dir_perms )
2006-01-31 03:48:57 +03:00
{
2012-03-14 13:46:14 +04:00
int ret ;
2013-01-08 17:21:00 +04:00
struct stat st ;
2012-03-14 13:46:14 +04:00
ret = lstat ( dname , & st ) ;
if ( ret = = - 1 ) {
2012-03-14 13:52:50 +04:00
mode_t old_umask ;
2012-03-14 13:43:54 +04:00
if ( errno ! = ENOENT ) {
2006-01-31 03:48:57 +03:00
DEBUG ( 0 , ( " lstat failed on directory %s: %s \n " ,
dname , strerror ( errno ) ) ) ;
2007-08-27 21:21:16 +04:00
return false ;
2006-01-31 03:48:57 +03:00
}
2012-03-14 13:41:47 +04:00
2012-03-14 13:43:54 +04:00
/* Create directory */
2012-03-14 13:52:50 +04:00
old_umask = umask ( 0 ) ;
2012-03-14 13:46:14 +04:00
ret = mkdir ( dname , dir_perms ) ;
2012-03-14 13:50:34 +04:00
if ( ret = = - 1 & & errno ! = EEXIST ) {
2012-03-14 13:43:54 +04:00
DEBUG ( 0 , ( " mkdir failed on directory "
" %s: %s \n " , dname ,
strerror ( errno ) ) ) ;
umask ( old_umask ) ;
return false ;
}
2012-03-14 13:52:50 +04:00
umask ( old_umask ) ;
2012-03-14 13:43:54 +04:00
2012-03-14 13:50:34 +04:00
ret = lstat ( dname , & st ) ;
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " lstat failed on created directory %s: %s \n " ,
dname , strerror ( errno ) ) ) ;
return false ;
}
2006-01-31 03:48:57 +03:00
}
2012-03-14 13:41:47 +04:00
2013-01-08 17:21:00 +04:00
return true ;
}
/**
* @ brief Try to create a specified directory if it doesn ' t exist .
*
* The function creates a directory with the given uid and permissions if it
* doesn ' t exixt . If it exists it makes sure the uid and permissions are
* correct and it will fail if they are different .
*
* @ param [ in ] dname The directory to create .
*
* @ param [ in ] uid The uid the directory needs to belong too .
*
* @ param [ in ] dir_perms The expected permissions of the directory .
*
* @ return True on success , false on error .
*/
_PUBLIC_ bool directory_create_or_exist_strict ( const char * dname ,
uid_t uid ,
mode_t dir_perms )
{
struct stat st ;
bool ok ;
int rc ;
ok = directory_create_or_exist ( dname , uid , dir_perms ) ;
if ( ! ok ) {
return false ;
}
rc = lstat ( dname , & st ) ;
if ( rc = = - 1 ) {
DEBUG ( 0 , ( " lstat failed on created directory %s: %s \n " ,
dname , strerror ( errno ) ) ) ;
return false ;
}
2012-03-14 13:41:47 +04:00
/* Check ownership and permission on existing directory */
if ( ! S_ISDIR ( st . st_mode ) ) {
DEBUG ( 0 , ( " directory %s isn't a directory \n " ,
dname ) ) ;
return false ;
}
if ( st . st_uid ! = uid & & ! uwrap_enabled ( ) ) {
DEBUG ( 0 , ( " invalid ownership on directory "
" %s \n " , dname ) ) ;
return false ;
}
if ( ( st . st_mode & 0777 ) ! = dir_perms ) {
DEBUG ( 0 , ( " invalid permissions on directory "
" '%s': has 0%o should be 0%o \n " , dname ,
( st . st_mode & 0777 ) , dir_perms ) ) ;
return false ;
}
2007-08-27 21:21:16 +04:00
return true ;
2013-01-08 17:21:00 +04:00
}
2006-01-31 03:48:57 +03:00
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Sleep for a specified number of milliseconds .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2010-09-16 23:36:37 +04:00
_PUBLIC_ void smb_msleep ( unsigned int t )
2003-08-13 05:53:07 +04:00
{
2010-09-16 23:36:37 +04:00
# if defined(HAVE_NANOSLEEP)
struct timespec ts ;
int ret ;
2003-08-13 05:53:07 +04:00
2010-09-16 23:36:37 +04:00
ts . tv_sec = t / 1000 ;
ts . tv_nsec = 1000000 * ( t % 1000 ) ;
do {
errno = 0 ;
ret = nanosleep ( & ts , & ts ) ;
} while ( ret < 0 & & errno = = EINTR & & ( ts . tv_sec > 0 | | ts . tv_nsec > 0 ) ) ;
# else
unsigned int tdiff = 0 ;
struct timeval tval , t1 , t2 ;
fd_set fds ;
GetTimeOfDay ( & t1 ) ;
t2 = t1 ;
while ( tdiff < t ) {
tval . tv_sec = ( t - tdiff ) / 1000 ;
tval . tv_usec = 1000 * ( ( t - tdiff ) % 1000 ) ;
/* Never wait for more than 1 sec. */
if ( tval . tv_sec > 1 ) {
tval . tv_sec = 1 ;
tval . tv_usec = 0 ;
}
FD_ZERO ( & fds ) ;
errno = 0 ;
select ( 0 , & fds , NULL , NULL , & tval ) ;
GetTimeOfDay ( & t2 ) ;
if ( t2 . tv_sec < t1 . tv_sec ) {
/* Someone adjusted time... */
t1 = t2 ;
}
2010-09-17 16:05:53 +04:00
tdiff = usec_time_diff ( & t2 , & t1 ) / 1000 ;
2010-09-16 23:36:37 +04:00
}
# endif
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2009-02-13 12:56:34 +03:00
Get my own name , return in talloc ' ed storage .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2009-02-13 12:56:34 +03:00
_PUBLIC_ char * get_myname ( TALLOC_CTX * ctx )
2003-08-13 05:53:07 +04:00
{
char * p ;
2009-02-13 12:56:34 +03:00
char hostname [ HOST_NAME_MAX ] ;
2003-08-13 05:53:07 +04:00
/* get my host name */
2009-02-13 12:56:34 +03:00
if ( gethostname ( hostname , sizeof ( hostname ) ) = = - 1 ) {
2003-08-13 05:53:07 +04:00
DEBUG ( 0 , ( " gethostname failed \n " ) ) ;
return NULL ;
2009-02-13 12:56:34 +03:00
}
2003-08-13 05:53:07 +04:00
/* Ensure null termination. */
2009-02-13 12:56:34 +03:00
hostname [ sizeof ( hostname ) - 1 ] = ' \0 ' ;
2003-08-13 05:53:07 +04:00
/* split off any parts after an initial . */
2009-02-13 12:56:34 +03:00
p = strchr_m ( hostname , ' . ' ) ;
if ( p ) {
2003-08-13 05:53:07 +04:00
* p = 0 ;
2009-02-13 12:56:34 +03:00
}
return talloc_strdup ( ctx , hostname ) ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Check if a process exists . Does this work on all unixes ?
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2008-10-17 14:26:46 +04:00
_PUBLIC_ bool process_exists_by_pid ( pid_t pid )
2003-08-13 05:53:07 +04:00
{
/* Doing kill with a non-positive pid causes messages to be
* sent to places we don ' t want . */
2012-08-22 19:52:01 +04:00
if ( pid < = 0 ) {
return false ;
}
2003-08-13 05:53:07 +04:00
return ( kill ( pid , 0 ) = = 0 | | errno ! = ESRCH ) ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Simple routine to do POSIX file locking . Cruft in NFS and 64 - > 32 bit mapping
is dealt with in posix . c
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool fcntl_lock ( int fd , int op , off_t offset , off_t count , int type )
2003-08-13 05:53:07 +04:00
{
2004-11-01 23:21:54 +03:00
struct flock lock ;
2003-08-13 05:53:07 +04:00
int ret ;
DEBUG ( 8 , ( " fcntl_lock %d %d %.0f %.0f %d \n " , fd , op , ( double ) offset , ( double ) count , type ) ) ;
lock . l_type = type ;
lock . l_whence = SEEK_SET ;
lock . l_start = offset ;
lock . l_len = count ;
lock . l_pid = 0 ;
2004-11-01 23:21:54 +03:00
ret = fcntl ( fd , op , & lock ) ;
2003-08-13 05:53:07 +04:00
if ( ret = = - 1 & & errno ! = 0 )
DEBUG ( 3 , ( " fcntl_lock: fcntl lock gave errno %d (%s) \n " , errno , strerror ( errno ) ) ) ;
/* a lock query */
2004-11-01 23:21:54 +03:00
if ( op = = F_GETLK ) {
2003-08-13 05:53:07 +04:00
if ( ( ret ! = - 1 ) & &
( lock . l_type ! = F_UNLCK ) & &
( lock . l_pid ! = 0 ) & &
( lock . l_pid ! = getpid ( ) ) ) {
DEBUG ( 3 , ( " fcntl_lock: fd %d is locked by pid %d \n " , fd , ( int ) lock . l_pid ) ) ;
2007-08-27 21:21:16 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
/* it must be not locked or locked by me */
2007-08-27 21:21:16 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
/* a lock set or unset */
if ( ret = = - 1 ) {
DEBUG ( 3 , ( " fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s) \n " ,
( double ) offset , ( double ) count , op , type , strerror ( errno ) ) ) ;
2007-08-27 21:21:16 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
/* everything went OK */
DEBUG ( 8 , ( " fcntl_lock: Lock call successful \n " ) ) ;
2007-08-27 21:21:16 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2010-10-24 17:23:41 +04:00
static void debugadd_cb ( const char * buf , void * private_data )
{
int * plevel = ( int * ) private_data ;
DEBUGADD ( * plevel , ( " %s " , buf ) ) ;
}
void print_asc_cb ( const uint8_t * buf , int len ,
void ( * cb ) ( const char * buf , void * private_data ) ,
void * private_data )
2003-08-13 05:53:07 +04:00
{
int i ;
2010-10-24 17:23:41 +04:00
char s [ 2 ] ;
s [ 1 ] = 0 ;
for ( i = 0 ; i < len ; i + + ) {
s [ 0 ] = isprint ( buf [ i ] ) ? buf [ i ] : ' . ' ;
cb ( s , private_data ) ;
}
}
void print_asc ( int level , const uint8_t * buf , int len )
{
print_asc_cb ( buf , len , debugadd_cb , & level ) ;
2003-08-13 05:53:07 +04:00
}
2006-03-06 03:24:51 +03:00
/**
2010-10-24 17:42:45 +04:00
* Write dump of binary data to a callback
2006-03-06 03:24:51 +03:00
*/
2010-10-24 17:42:45 +04:00
void dump_data_cb ( const uint8_t * buf , int len ,
bool omit_zero_bytes ,
void ( * cb ) ( const char * buf , void * private_data ) ,
void * private_data )
2003-08-13 05:53:07 +04:00
{
int i = 0 ;
2009-07-25 20:56:06 +04:00
static const uint8_t empty [ 16 ] = { 0 , } ;
2007-11-02 13:33:53 +03:00
bool skipped = false ;
2010-10-24 17:42:45 +04:00
char tmp [ 16 ] ;
2007-11-02 13:33:53 +03:00
2003-08-13 05:53:07 +04:00
if ( len < = 0 ) return ;
for ( i = 0 ; i < len ; ) {
2007-11-02 13:33:53 +03:00
if ( i % 16 = = 0 ) {
if ( ( omit_zero_bytes = = true ) & &
( i > 0 ) & &
( len > i + 16 ) & &
( memcmp ( & buf [ i ] , & empty , 16 ) = = 0 ) )
{
i + = 16 ;
continue ;
}
if ( i < len ) {
2010-10-24 17:42:45 +04:00
snprintf ( tmp , sizeof ( tmp ) , " [%04X] " , i ) ;
cb ( tmp , private_data ) ;
2007-11-02 13:33:53 +03:00
}
}
2010-10-24 17:42:45 +04:00
snprintf ( tmp , sizeof ( tmp ) , " %02X " , ( int ) buf [ i ] ) ;
cb ( tmp , private_data ) ;
2003-08-13 05:53:07 +04:00
i + + ;
2010-10-24 17:42:45 +04:00
if ( i % 8 = = 0 ) {
cb ( " " , private_data ) ;
}
2007-11-02 13:33:53 +03:00
if ( i % 16 = = 0 ) {
2010-10-24 17:42:45 +04:00
print_asc_cb ( & buf [ i - 16 ] , 8 , cb , private_data ) ;
cb ( " " , private_data ) ;
print_asc_cb ( & buf [ i - 8 ] , 8 , cb , private_data ) ;
cb ( " \n " , private_data ) ;
2007-11-02 13:33:53 +03:00
if ( ( omit_zero_bytes = = true ) & &
( len > i + 16 ) & &
( memcmp ( & buf [ i ] , & empty , 16 ) = = 0 ) ) {
if ( ! skipped ) {
2010-10-24 17:42:45 +04:00
cb ( " skipping zero buffer bytes \n " ,
private_data ) ;
2007-11-02 13:33:53 +03:00
skipped = true ;
}
}
2003-08-13 05:53:07 +04:00
}
}
2007-11-02 13:33:53 +03:00
2003-08-13 05:53:07 +04:00
if ( i % 16 ) {
int n ;
n = 16 - ( i % 16 ) ;
2010-10-24 17:42:45 +04:00
cb ( " " , private_data ) ;
if ( n > 8 ) {
cb ( " " , private_data ) ;
}
while ( n - - ) {
cb ( " " , private_data ) ;
}
2003-08-13 05:53:07 +04:00
n = MIN ( 8 , i % 16 ) ;
2010-10-24 17:42:45 +04:00
print_asc_cb ( & buf [ i - ( i % 16 ) ] , n , cb , private_data ) ;
cb ( " " , private_data ) ;
2003-08-13 05:53:07 +04:00
n = ( i % 16 ) - n ;
2010-10-24 17:42:45 +04:00
if ( n > 0 ) {
print_asc_cb ( & buf [ i - n ] , n , cb , private_data ) ;
}
cb ( " \n " , private_data ) ;
2007-11-02 13:33:53 +03:00
}
2003-08-13 05:53:07 +04:00
}
2007-11-02 13:33:53 +03:00
/**
* Write dump of binary data to the log file .
*
* The data is only written if the log level is at least level .
*/
_PUBLIC_ void dump_data ( int level , const uint8_t * buf , int len )
{
2010-10-24 17:42:45 +04:00
if ( ! DEBUGLVL ( level ) ) {
return ;
}
dump_data_cb ( buf , len , false , debugadd_cb , & level ) ;
2007-11-02 13:33:53 +03:00
}
/**
* Write dump of binary data to the log file .
*
* The data is only written if the log level is at least level .
2010-02-21 08:58:07 +03:00
* 16 zero bytes in a row are omitted
2007-11-02 13:33:53 +03:00
*/
_PUBLIC_ void dump_data_skip_zeros ( int level , const uint8_t * buf , int len )
{
2010-10-24 17:42:45 +04:00
if ( ! DEBUGLVL ( level ) ) {
return ;
}
dump_data_cb ( buf , len , true , debugadd_cb , & level ) ;
2007-11-02 13:33:53 +03:00
}
2012-01-25 12:10:04 +04:00
static void fprintf_cb ( const char * buf , void * private_data )
{
FILE * f = ( FILE * ) private_data ;
fprintf ( f , " %s " , buf ) ;
}
void dump_data_file ( const uint8_t * buf , int len , bool omit_zero_bytes ,
FILE * f )
{
dump_data_cb ( buf , len , omit_zero_bytes , fprintf_cb , f ) ;
}
2007-11-02 13:33:53 +03:00
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
malloc that aborts with smb_panic on fail or zero size .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-03-05 20:15:19 +03:00
_PUBLIC_ void * smb_xmalloc ( size_t size )
2003-08-13 05:53:07 +04:00
{
void * p ;
if ( size = = 0 )
smb_panic ( " smb_xmalloc: called with zero size. \n " ) ;
if ( ( p = malloc ( size ) ) = = NULL )
smb_panic ( " smb_xmalloc: malloc fail. \n " ) ;
return p ;
}
/**
Memdup with smb_panic on fail .
* */
2006-03-05 20:15:19 +03:00
_PUBLIC_ void * smb_xmemdup ( const void * p , size_t size )
2003-08-13 05:53:07 +04:00
{
void * p2 ;
p2 = smb_xmalloc ( size ) ;
memcpy ( p2 , p , size ) ;
return p2 ;
}
/**
strdup that aborts on malloc fail .
* */
2008-10-17 14:26:46 +04:00
char * smb_xstrdup ( const char * s )
2003-08-13 05:53:07 +04:00
{
2008-10-17 14:26:46 +04:00
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strdup
# undef strdup
# endif
# endif
# ifndef HAVE_STRDUP
# define strdup rep_strdup
# endif
2003-08-13 05:53:07 +04:00
char * s1 = strdup ( s ) ;
2008-10-17 14:26:46 +04:00
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strdup
# undef strdup
# endif
# define strdup(s) __ERROR_DONT_USE_STRDUP_DIRECTLY
# endif
if ( ! s1 ) {
smb_panic ( " smb_xstrdup: malloc failed " ) ;
}
return s1 ;
}
/**
strndup that aborts on malloc fail .
* */
char * smb_xstrndup ( const char * s , size_t n )
{
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strndup
# undef strndup
# endif
# endif
# if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP))
# undef HAVE_STRNDUP
# define strndup rep_strndup
# endif
char * s1 = strndup ( s , n ) ;
# if defined(PARANOID_MALLOC_CHECKER)
# ifdef strndup
# undef strndup
# endif
# define strndup(s,n) __ERROR_DONT_USE_STRNDUP_DIRECTLY
# endif
if ( ! s1 ) {
smb_panic ( " smb_xstrndup: malloc failed " ) ;
}
2003-08-13 05:53:07 +04:00
return s1 ;
}
2008-10-17 14:26:46 +04:00
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
Like strdup but for memory .
2006-02-28 16:12:39 +03:00
* */
2003-08-13 05:53:07 +04:00
2006-03-05 20:15:19 +03:00
_PUBLIC_ void * memdup ( const void * p , size_t size )
2003-08-13 05:53:07 +04:00
{
void * p2 ;
if ( size = = 0 )
return NULL ;
p2 = malloc ( size ) ;
if ( ! p2 )
return NULL ;
memcpy ( p2 , p , size ) ;
return p2 ;
}
2006-03-06 03:24:51 +03:00
/**
* Write a password to the log file .
*
* @ note Only actually does something if DEBUG_PASSWORD was defined during
* compile - time .
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ void dump_data_pw ( const char * msg , const uint8_t * data , size_t len )
2003-11-26 04:16:41 +03:00
{
# ifdef DEBUG_PASSWORD
DEBUG ( 11 , ( " %s " , msg ) ) ;
if ( data ! = NULL & & len > 0 )
{
dump_data ( 11 , data , len ) ;
}
# endif
}
2003-12-13 05:20:40 +03:00
2006-02-28 16:12:39 +03:00
/**
* see if a range of memory is all zero . A NULL pointer is considered
* to be all zero
*/
2007-08-27 21:21:16 +04:00
_PUBLIC_ bool all_zero ( const uint8_t * ptr , size_t size )
2003-12-13 05:20:40 +03:00
{
int i ;
2007-08-27 21:21:16 +04:00
if ( ! ptr ) return true ;
2003-12-13 05:20:40 +03:00
for ( i = 0 ; i < size ; i + + ) {
2007-08-27 21:21:16 +04:00
if ( ptr [ i ] ) return false ;
2003-12-13 05:20:40 +03:00
}
2007-08-27 21:21:16 +04:00
return true ;
2003-12-13 05:20:40 +03:00
}
2004-12-03 09:24:38 +03:00
2006-02-28 16:12:39 +03:00
/**
2004-12-03 09:24:38 +03:00
realloc an array , checking for integer overflow in the array size
*/
2008-10-18 16:12:56 +04:00
_PUBLIC_ void * realloc_array ( void * ptr , size_t el_size , unsigned count , bool free_on_fail )
2004-12-03 09:24:38 +03:00
{
# define MAX_MALLOC_SIZE 0x7fffffff
if ( count = = 0 | |
count > = MAX_MALLOC_SIZE / el_size ) {
2008-10-18 16:12:56 +04:00
if ( free_on_fail )
SAFE_FREE ( ptr ) ;
2004-12-03 09:24:38 +03:00
return NULL ;
}
if ( ! ptr ) {
return malloc ( el_size * count ) ;
}
return realloc ( ptr , el_size * count ) ;
}
2008-10-11 21:44:10 +04:00
/****************************************************************************
Type - safe malloc .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * malloc_array ( size_t el_size , unsigned int count )
{
2008-10-18 16:12:56 +04:00
return realloc_array ( NULL , el_size , count , false ) ;
2008-10-11 21:44:10 +04:00
}
2012-03-24 18:19:09 +04:00
/****************************************************************************
Type - safe memalign
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * memalign_array ( size_t el_size , size_t align , unsigned int count )
{
if ( count * el_size > = MAX_MALLOC_SIZE ) {
return NULL ;
}
return memalign ( align , el_size * count ) ;
}
/****************************************************************************
Type - safe calloc .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * calloc_array ( size_t size , size_t nmemb )
{
if ( nmemb > = MAX_MALLOC_SIZE / size ) {
return NULL ;
}
if ( size = = 0 | | nmemb = = 0 ) {
return NULL ;
}
return calloc ( nmemb , size ) ;
}
2008-10-19 14:38:16 +04:00
/**
Trim the specified elements off the front and back of a string .
* */
_PUBLIC_ bool trim_string ( char * s , const char * front , const char * back )
{
bool ret = false ;
size_t front_len ;
size_t back_len ;
size_t len ;
/* Ignore null or empty strings. */
if ( ! s | | ( s [ 0 ] = = ' \0 ' ) )
return false ;
front_len = front ? strlen ( front ) : 0 ;
back_len = back ? strlen ( back ) : 0 ;
len = strlen ( s ) ;
if ( front_len ) {
while ( len & & strncmp ( s , front , front_len ) = = 0 ) {
/* Must use memmove here as src & dest can
* easily overlap . Found by valgrind . JRA . */
memmove ( s , s + front_len , ( len - front_len ) + 1 ) ;
len - = front_len ;
ret = true ;
}
}
if ( back_len ) {
while ( ( len > = back_len ) & & strncmp ( s + len - back_len , back , back_len ) = = 0 ) {
s [ len - back_len ] = ' \0 ' ;
len - = back_len ;
ret = true ;
}
}
return ret ;
}
/**
Find the number of ' c ' chars in a string
* */
_PUBLIC_ _PURE_ size_t count_chars ( const char * s , char c )
{
size_t count = 0 ;
while ( * s ) {
if ( * s = = c ) count + + ;
s + + ;
}
return count ;
}
/**
2011-10-18 20:07:54 +04:00
* Routine to get hex characters and turn them into a byte array .
* the array can be variable length .
* - " 0xnn " or " 0Xnn " is specially catered for .
* - The first non - hex - digit character ( apart from possibly leading " 0x "
* finishes the conversion and skips the rest of the input .
2011-10-18 20:10:00 +04:00
* - A single hex - digit character at the end of the string is skipped .
2011-10-18 20:07:54 +04:00
*
* valid examples : " 0A5D15 " ; " 0x123456 "
*/
2008-10-19 14:38:16 +04:00
_PUBLIC_ size_t strhex_to_str ( char * p , size_t p_len , const char * strhex , size_t strhex_len )
{
2009-09-26 00:40:55 +04:00
size_t i = 0 ;
2008-10-19 14:38:16 +04:00
size_t num_chars = 0 ;
uint8_t lonybble , hinybble ;
const char * hexchars = " 0123456789ABCDEF " ;
char * p1 = NULL , * p2 = NULL ;
2009-09-26 00:40:55 +04:00
/* skip leading 0x prefix */
if ( strncasecmp ( strhex , " 0x " , 2 ) = = 0 ) {
i + = 2 ; /* skip two chars */
}
2008-10-19 14:38:16 +04:00
2011-10-18 20:10:00 +04:00
for ( ; i + 1 < strhex_len & & strhex [ i ] ! = 0 & & strhex [ i + 1 ] ! = 0 ; i + + ) {
2011-10-18 20:03:10 +04:00
p1 = strchr ( hexchars , toupper ( ( unsigned char ) strhex [ i ] ) ) ;
if ( p1 = = NULL ) {
2008-10-19 14:38:16 +04:00
break ;
2011-10-18 20:03:10 +04:00
}
2008-10-19 14:38:16 +04:00
i + + ; /* next hex digit */
2011-10-18 20:03:10 +04:00
p2 = strchr ( hexchars , toupper ( ( unsigned char ) strhex [ i ] ) ) ;
if ( p2 = = NULL ) {
2008-10-19 14:38:16 +04:00
break ;
2011-10-18 20:03:10 +04:00
}
2008-10-19 14:38:16 +04:00
/* get the two nybbles */
hinybble = PTR_DIFF ( p1 , hexchars ) ;
lonybble = PTR_DIFF ( p2 , hexchars ) ;
if ( num_chars > = p_len ) {
break ;
}
p [ num_chars ] = ( hinybble < < 4 ) | lonybble ;
num_chars + + ;
p1 = NULL ;
p2 = NULL ;
}
return num_chars ;
}
/**
* Parse a hex string and return a data blob .
*/
_PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob ( TALLOC_CTX * mem_ctx , const char * strhex )
{
DATA_BLOB ret_blob = data_blob_talloc ( mem_ctx , NULL , strlen ( strhex ) / 2 + 1 ) ;
ret_blob . length = strhex_to_str ( ( char * ) ret_blob . data , ret_blob . length ,
strhex ,
strlen ( strhex ) ) ;
return ret_blob ;
}
2012-02-03 06:27:19 +04:00
/**
* Print a buf in hex . Assumes dst is at least ( srclen * 2 ) + 1 large .
*/
_PUBLIC_ void hex_encode_buf ( char * dst , const uint8_t * src , size_t srclen )
{
size_t i ;
for ( i = 0 ; i < srclen ; i + + ) {
snprintf ( dst + i * 2 , 3 , " %02X " , src [ i ] ) ;
}
/*
* Ensure 0 - termination for 0 - length buffers
*/
dst [ srclen * 2 ] = ' \0 ' ;
}
2008-10-19 14:38:16 +04:00
/**
* Routine to print a buffer as HEX digits , into an allocated string .
*/
_PUBLIC_ void hex_encode ( const unsigned char * buff_in , size_t len , char * * out_hex_buffer )
{
char * hex_buffer ;
* out_hex_buffer = malloc_array_p ( char , ( len * 2 ) + 1 ) ;
hex_buffer = * out_hex_buffer ;
2012-02-03 06:27:19 +04:00
hex_encode_buf ( hex_buffer , buff_in , len ) ;
2008-10-19 14:38:16 +04:00
}
/**
* talloc version of hex_encode ( )
*/
_PUBLIC_ char * hex_encode_talloc ( TALLOC_CTX * mem_ctx , const unsigned char * buff_in , size_t len )
{
char * hex_buffer ;
hex_buffer = talloc_array ( mem_ctx , char , ( len * 2 ) + 1 ) ;
2008-11-13 23:26:03 +03:00
if ( ! hex_buffer ) {
return NULL ;
}
2012-02-03 06:27:19 +04:00
hex_encode_buf ( hex_buffer , buff_in , len ) ;
2008-11-13 23:26:03 +03:00
talloc_set_name_const ( hex_buffer , hex_buffer ) ;
2008-10-19 14:38:16 +04:00
return hex_buffer ;
}
/**
varient of strcmp ( ) that handles NULL ptrs
* */
_PUBLIC_ int strcmp_safe ( const char * s1 , const char * s2 )
{
if ( s1 = = s2 ) {
return 0 ;
}
if ( s1 = = NULL | | s2 = = NULL ) {
return s1 ? - 1 : 1 ;
}
return strcmp ( s1 , s2 ) ;
}
/**
return the number of bytes occupied by a buffer in ASCII format
the result includes the null termination
limited by ' n ' bytes
* */
_PUBLIC_ size_t ascii_len_n ( const char * src , size_t n )
{
size_t len ;
len = strnlen ( src , n ) ;
if ( len + 1 < = n ) {
len + = 1 ;
}
return len ;
}
/**
Set a boolean variable from the text value stored in the passed string .
Returns true in success , false if the passed string does not correctly
represent a boolean .
* */
_PUBLIC_ bool set_boolean ( const char * boolean_string , bool * boolean )
{
if ( strwicmp ( boolean_string , " yes " ) = = 0 | |
strwicmp ( boolean_string , " true " ) = = 0 | |
strwicmp ( boolean_string , " on " ) = = 0 | |
strwicmp ( boolean_string , " 1 " ) = = 0 ) {
* boolean = true ;
return true ;
} else if ( strwicmp ( boolean_string , " no " ) = = 0 | |
strwicmp ( boolean_string , " false " ) = = 0 | |
strwicmp ( boolean_string , " off " ) = = 0 | |
strwicmp ( boolean_string , " 0 " ) = = 0 ) {
* boolean = false ;
return true ;
}
return false ;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
* */
_PUBLIC_ size_t utf16_len ( const void * buf )
{
size_t len ;
for ( len = 0 ; SVAL ( buf , len ) ; len + = 2 ) ;
return len + 2 ;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
limited by ' n ' bytes
* */
_PUBLIC_ size_t utf16_len_n ( const void * src , size_t n )
{
size_t len ;
for ( len = 0 ; ( len + 2 < n ) & & SVAL ( src , len ) ; len + = 2 ) ;
if ( len + 2 < = n ) {
len + = 2 ;
}
return len ;
}
2009-03-01 18:19:38 +03:00
/**
* @ file
* @ brief String utilities .
* */
static bool next_token_internal_talloc ( TALLOC_CTX * ctx ,
const char * * ptr ,
char * * pp_buff ,
const char * sep ,
bool ltrim )
{
2009-09-26 00:40:04 +04:00
const char * s ;
const char * saved_s ;
2009-03-01 18:19:38 +03:00
char * pbuf ;
bool quoted ;
size_t len = 1 ;
* pp_buff = NULL ;
if ( ! ptr ) {
return ( false ) ;
}
2009-09-26 00:40:04 +04:00
s = * ptr ;
2009-03-01 18:19:38 +03:00
/* default to simple separators */
if ( ! sep ) {
sep = " \t \n \r " ;
}
/* find the first non sep char, if left-trimming is requested */
if ( ltrim ) {
while ( * s & & strchr_m ( sep , * s ) ) {
s + + ;
}
}
/* nothing left? */
if ( ! * s ) {
return false ;
}
/* When restarting we need to go from here. */
saved_s = s ;
/* Work out the length needed. */
for ( quoted = false ; * s & &
( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
len + + ;
}
}
/* We started with len = 1 so we have space for the nul. */
* pp_buff = talloc_array ( ctx , char , len ) ;
if ( ! * pp_buff ) {
return false ;
}
/* copy over the token */
pbuf = * pp_buff ;
s = saved_s ;
for ( quoted = false ; * s & &
( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
* pbuf + + = * s ;
}
}
* ptr = ( * s ) ? s + 1 : s ;
* pbuf = 0 ;
return true ;
}
bool next_token_talloc ( TALLOC_CTX * ctx ,
const char * * ptr ,
char * * pp_buff ,
const char * sep )
{
return next_token_internal_talloc ( ctx , ptr , pp_buff , sep , true ) ;
}
/*
* Get the next token from a string , return false if none found . Handles
* double - quotes . This version does not trim leading separator characters
* before looking for a token .
*/
bool next_token_no_ltrim_talloc ( TALLOC_CTX * ctx ,
const char * * ptr ,
char * * pp_buff ,
const char * sep )
{
return next_token_internal_talloc ( ctx , ptr , pp_buff , sep , false ) ;
}
2011-03-09 18:34:49 +03:00
/**
* Get the next token from a string , return False if none found .
* Handles double - quotes .
*
* Based on a routine by GJC @ VILLAGE . COM .
* Extensively modified by Andrew . Tridgell @ anu . edu . au
* */
_PUBLIC_ bool next_token ( const char * * ptr , char * buff , const char * sep , size_t bufsize )
{
const char * s ;
bool quoted ;
size_t len = 1 ;
if ( ! ptr )
return false ;
s = * ptr ;
/* default to simple separators */
if ( ! sep )
sep = " \t \n \r " ;
/* find the first non sep char */
while ( * s & & strchr_m ( sep , * s ) )
s + + ;
/* nothing left? */
if ( ! * s )
return false ;
/* copy over the token */
for ( quoted = false ; len < bufsize & & * s & & ( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
if ( * s = = ' \" ' ) {
quoted = ! quoted ;
} else {
len + + ;
* buff + + = * s ;
}
}
* ptr = ( * s ) ? s + 1 : s ;
* buff = 0 ;
return true ;
}
2010-10-27 00:45:19 +04:00
struct anonymous_shared_header {
union {
size_t length ;
uint8_t pad [ 16 ] ;
} u ;
} ;
2010-03-22 10:27:58 +03:00
/* Map a shared memory buffer of at least nelem counters. */
2010-10-27 00:45:19 +04:00
void * anonymous_shared_allocate ( size_t orig_bufsz )
2010-03-22 10:27:58 +03:00
{
2010-10-27 00:45:19 +04:00
void * ptr ;
2010-03-22 10:27:58 +03:00
void * buf ;
size_t pagesz = getpagesize ( ) ;
2011-01-19 19:55:13 +03:00
size_t pagecnt ;
2010-10-27 00:45:19 +04:00
size_t bufsz = orig_bufsz ;
struct anonymous_shared_header * hdr ;
bufsz + = sizeof ( * hdr ) ;
2010-03-22 10:27:58 +03:00
2011-01-19 19:55:13 +03:00
/* round up to full pages */
pagecnt = bufsz / pagesz ;
2010-03-22 10:27:58 +03:00
if ( bufsz % pagesz ) {
2011-01-19 19:55:13 +03:00
pagecnt + = 1 ;
2010-03-22 10:27:58 +03:00
}
2011-01-19 19:55:13 +03:00
bufsz = pagesz * pagecnt ;
2010-03-22 10:27:58 +03:00
2010-10-27 00:45:19 +04:00
if ( orig_bufsz > = bufsz ) {
/* integer wrap */
errno = ENOMEM ;
return NULL ;
}
2010-03-22 10:27:58 +03:00
# ifdef MAP_ANON
/* BSD */
buf = mmap ( NULL , bufsz , PROT_READ | PROT_WRITE , MAP_ANON | MAP_SHARED ,
- 1 /* fd */ , 0 /* offset */ ) ;
# else
2012-06-26 15:48:36 +04:00
{
int saved_errno ;
int fd ;
fd = open ( " /dev/zero " , O_RDWR ) ;
if ( fd = = - 1 ) {
return NULL ;
}
2010-03-22 10:27:58 +03:00
buf = mmap ( NULL , bufsz , PROT_READ | PROT_WRITE , MAP_FILE | MAP_SHARED ,
2012-06-26 15:48:36 +04:00
fd , 0 /* offset */ ) ;
saved_errno = errno ;
close ( fd ) ;
errno = saved_errno ;
}
2010-03-22 10:27:58 +03:00
# endif
if ( buf = = MAP_FAILED ) {
return NULL ;
}
2010-10-27 00:45:19 +04:00
hdr = ( struct anonymous_shared_header * ) buf ;
hdr - > u . length = bufsz ;
ptr = ( void * ) ( & hdr [ 1 ] ) ;
return ptr ;
}
2011-08-15 02:10:53 +04:00
void * anonymous_shared_resize ( void * ptr , size_t new_size , bool maymove )
{
# ifdef HAVE_MREMAP
void * buf ;
size_t pagesz = getpagesize ( ) ;
size_t pagecnt ;
size_t bufsz ;
struct anonymous_shared_header * hdr ;
int flags = 0 ;
if ( ptr = = NULL ) {
errno = EINVAL ;
return NULL ;
}
hdr = ( struct anonymous_shared_header * ) ptr ;
hdr - - ;
if ( hdr - > u . length > ( new_size + sizeof ( * hdr ) ) ) {
errno = EINVAL ;
return NULL ;
}
bufsz = new_size + sizeof ( * hdr ) ;
/* round up to full pages */
pagecnt = bufsz / pagesz ;
if ( bufsz % pagesz ) {
pagecnt + = 1 ;
}
bufsz = pagesz * pagecnt ;
if ( new_size > = bufsz ) {
/* integer wrap */
errno = ENOSPC ;
return NULL ;
}
if ( bufsz < = hdr - > u . length ) {
return ptr ;
}
if ( maymove ) {
flags = MREMAP_MAYMOVE ;
}
buf = mremap ( hdr , hdr - > u . length , bufsz , flags ) ;
if ( buf = = MAP_FAILED ) {
errno = ENOSPC ;
return NULL ;
}
hdr = ( struct anonymous_shared_header * ) buf ;
hdr - > u . length = bufsz ;
ptr = ( void * ) ( & hdr [ 1 ] ) ;
return ptr ;
# else
errno = ENOSPC ;
return NULL ;
# endif
}
2010-10-27 00:45:19 +04:00
void anonymous_shared_free ( void * ptr )
{
struct anonymous_shared_header * hdr ;
if ( ptr = = NULL ) {
return ;
}
hdr = ( struct anonymous_shared_header * ) ptr ;
hdr - - ;
2010-03-22 10:27:58 +03:00
2010-10-27 00:45:19 +04:00
munmap ( hdr , hdr - > u . length ) ;
2010-03-22 10:27:58 +03:00
}
2008-10-19 14:38:16 +04:00
2010-07-20 09:31:49 +04:00
# ifdef DEVELOPER
/* used when you want a debugger started at a particular point in the
code . Mostly useful in code that runs as a child process , where
normal gdb attach is harder to organise .
*/
void samba_start_debugger ( void )
{
char * cmd = NULL ;
2010-09-09 13:10:01 +04:00
if ( asprintf ( & cmd , " xterm -e \" gdb --pid %u \" & " , getpid ( ) ) = = - 1 ) {
return ;
}
if ( system ( cmd ) = = - 1 ) {
free ( cmd ) ;
return ;
}
2010-07-20 09:31:49 +04:00
free ( cmd ) ;
sleep ( 2 ) ;
}
# endif