2014-02-24 16:23:49 +04:00
/*
* Unix SMB / CIFS implementation .
* Samba internal messaging functions
* Copyright ( C ) 2013 by Volker Lendecke
*
* 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
* the Free Software Foundation ; either version 3 of the License , or
* ( 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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "lib/util/data_blob.h"
# include "lib/util/debug.h"
# include "lib/unix_msg/unix_msg.h"
# include "system/filesys.h"
2014-07-17 15:57:51 +04:00
# include "lib/messages_dgm.h"
2014-02-24 16:23:49 +04:00
# include "lib/param/param.h"
# include "poll_funcs/poll_funcs_tevent.h"
# include "unix_msg/unix_msg.h"
2014-09-10 11:58:00 +04:00
struct sun_path_buf {
/*
* This will carry enough for a socket path
*/
char buf [ sizeof ( struct sockaddr_un ) ] ;
} ;
2014-02-24 16:23:49 +04:00
struct messaging_dgm_context {
2014-07-25 15:03:11 +04:00
pid_t pid ;
2014-05-05 10:45:52 +04:00
struct poll_funcs * msg_callbacks ;
void * tevent_handle ;
2014-02-24 16:23:49 +04:00
struct unix_msg_ctx * dgm_ctx ;
2014-10-04 12:58:15 +04:00
struct sun_path_buf socket_dir ;
struct sun_path_buf lockfile_dir ;
2014-02-24 16:23:49 +04:00
int lockfile_fd ;
2014-07-17 13:44:41 +04:00
2014-07-27 14:29:26 +04:00
void ( * recv_cb ) ( const uint8_t * msg ,
size_t msg_len ,
2014-09-30 13:29:22 +04:00
int * fds ,
2014-06-24 09:39:05 +04:00
size_t num_fds ,
2014-07-17 13:44:41 +04:00
void * private_data ) ;
void * recv_cb_private_data ;
2014-07-20 16:51:47 +04:00
bool * have_dgm_context ;
2014-02-24 16:23:49 +04:00
} ;
2014-09-10 18:13:18 +04:00
static struct messaging_dgm_context * global_dgm_context ;
2014-02-24 16:23:49 +04:00
static void messaging_dgm_recv ( struct unix_msg_ctx * ctx ,
uint8_t * msg , size_t msg_len ,
2014-06-23 19:16:32 +04:00
int * fds , size_t num_fds ,
2014-02-24 16:23:49 +04:00
void * private_data ) ;
static int messaging_dgm_context_destructor ( struct messaging_dgm_context * c ) ;
2014-10-04 12:58:15 +04:00
static int messaging_dgm_lockfile_create ( struct messaging_dgm_context * ctx ,
pid_t pid , int * plockfile_fd ,
uint64_t unique )
2014-02-24 16:23:49 +04:00
{
2014-06-03 00:29:44 +04:00
fstring buf ;
2014-02-24 16:23:49 +04:00
int lockfile_fd ;
2014-10-04 12:58:15 +04:00
struct sun_path_buf lockfile_name ;
2014-07-25 14:42:19 +04:00
struct flock lck ;
2014-02-24 16:23:49 +04:00
int unique_len , ret ;
ssize_t written ;
2014-10-04 12:58:15 +04:00
ret = snprintf ( lockfile_name . buf , sizeof ( lockfile_name . buf ) ,
" %s/%u " , ctx - > lockfile_dir . buf , ( int ) pid ) ;
if ( ret > = sizeof ( lockfile_name . buf ) ) {
return ENAMETOOLONG ;
2014-02-24 16:23:49 +04:00
}
/* no O_EXCL, existence check is via the fcntl lock */
2014-09-10 11:58:00 +04:00
lockfile_fd = open ( lockfile_name . buf , O_NONBLOCK | O_CREAT | O_WRONLY ,
0644 ) ;
2014-02-24 16:23:49 +04:00
if ( lockfile_fd = = - 1 ) {
ret = errno ;
DEBUG ( 1 , ( " %s: open failed: %s \n " , __func__ , strerror ( errno ) ) ) ;
2014-09-10 11:58:00 +04:00
return ret ;
2014-02-24 16:23:49 +04:00
}
2014-07-25 14:42:19 +04:00
lck = ( struct flock ) {
. l_type = F_WRLCK ,
. l_whence = SEEK_SET
} ;
2014-02-24 16:23:49 +04:00
ret = fcntl ( lockfile_fd , F_SETLK , & lck ) ;
if ( ret = = - 1 ) {
ret = errno ;
DEBUG ( 1 , ( " %s: fcntl failed: %s \n " , __func__ , strerror ( ret ) ) ) ;
goto fail_close ;
}
2014-08-02 15:57:43 +04:00
unique_len = snprintf ( buf , sizeof ( buf ) , " %ju \n " , ( uintmax_t ) unique ) ;
2014-02-24 16:23:49 +04:00
/* shorten a potentially preexisting file */
ret = ftruncate ( lockfile_fd , unique_len ) ;
if ( ret = = - 1 ) {
ret = errno ;
DEBUG ( 1 , ( " %s: ftruncate failed: %s \n " , __func__ ,
strerror ( ret ) ) ) ;
goto fail_unlink ;
}
written = write ( lockfile_fd , buf , unique_len ) ;
if ( written ! = unique_len ) {
ret = errno ;
DEBUG ( 1 , ( " %s: write failed: %s \n " , __func__ , strerror ( ret ) ) ) ;
goto fail_unlink ;
}
* plockfile_fd = lockfile_fd ;
return 0 ;
fail_unlink :
2014-09-10 11:58:00 +04:00
unlink ( lockfile_name . buf ) ;
2014-02-24 16:23:49 +04:00
fail_close :
close ( lockfile_fd ) ;
return ret ;
}
2014-09-10 18:13:18 +04:00
int messaging_dgm_init ( struct tevent_context * ev ,
2014-10-04 12:40:24 +04:00
uint64_t unique ,
2014-10-04 12:58:15 +04:00
const char * socket_dir ,
const char * lockfile_dir ,
2014-07-27 14:29:26 +04:00
void ( * recv_cb ) ( const uint8_t * msg ,
2014-07-17 13:44:41 +04:00
size_t msg_len ,
2014-09-30 13:29:22 +04:00
int * fds ,
2014-06-24 09:39:05 +04:00
size_t num_fds ,
2014-07-17 13:44:41 +04:00
void * private_data ) ,
2014-09-10 18:13:18 +04:00
void * recv_cb_private_data )
2014-02-24 16:23:49 +04:00
{
struct messaging_dgm_context * ctx ;
int ret ;
2014-06-01 22:57:21 +04:00
struct sockaddr_un socket_address ;
2014-10-04 12:58:15 +04:00
size_t len ;
2014-07-20 16:51:47 +04:00
static bool have_dgm_context = false ;
if ( have_dgm_context ) {
return EEXIST ;
}
2014-02-24 16:23:49 +04:00
2014-09-10 18:13:18 +04:00
ctx = talloc_zero ( NULL , struct messaging_dgm_context ) ;
2014-02-24 16:23:49 +04:00
if ( ctx = = NULL ) {
goto fail_nomem ;
}
2014-10-04 12:40:24 +04:00
ctx - > pid = getpid ( ) ;
2014-07-17 13:44:41 +04:00
ctx - > recv_cb = recv_cb ;
ctx - > recv_cb_private_data = recv_cb_private_data ;
2014-10-04 12:58:15 +04:00
len = strlcpy ( ctx - > lockfile_dir . buf , lockfile_dir ,
sizeof ( ctx - > lockfile_dir . buf ) ) ;
if ( len > = sizeof ( ctx - > lockfile_dir . buf ) ) {
2014-09-10 12:12:23 +04:00
TALLOC_FREE ( ctx ) ;
return ENAMETOOLONG ;
2014-02-24 16:23:49 +04:00
}
2014-06-01 22:57:21 +04:00
2014-10-04 12:58:15 +04:00
len = strlcpy ( ctx - > socket_dir . buf , socket_dir ,
sizeof ( ctx - > socket_dir . buf ) ) ;
if ( len > = sizeof ( ctx - > socket_dir . buf ) ) {
TALLOC_FREE ( ctx ) ;
return ENAMETOOLONG ;
}
2014-09-10 12:12:23 +04:00
2014-06-01 22:57:21 +04:00
socket_address = ( struct sockaddr_un ) { . sun_family = AF_UNIX } ;
2014-10-04 12:58:15 +04:00
len = snprintf ( socket_address . sun_path ,
sizeof ( socket_address . sun_path ) ,
" %s/%u " , socket_dir , ( unsigned ) ctx - > pid ) ;
if ( len > = sizeof ( socket_address . sun_path ) ) {
2014-07-17 15:23:46 +04:00
TALLOC_FREE ( ctx ) ;
2014-06-10 19:21:10 +04:00
return ENAMETOOLONG ;
2014-02-24 16:23:49 +04:00
}
2014-10-04 12:58:15 +04:00
ret = messaging_dgm_lockfile_create ( ctx , ctx - > pid , & ctx - > lockfile_fd ,
unique ) ;
2014-02-24 16:23:49 +04:00
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " %s: messaging_dgm_create_lockfile failed: %s \n " ,
__func__ , strerror ( ret ) ) ) ;
2014-07-17 15:23:46 +04:00
TALLOC_FREE ( ctx ) ;
2014-06-10 19:21:10 +04:00
return ret ;
2014-02-24 16:23:49 +04:00
}
2014-05-05 10:45:52 +04:00
ctx - > msg_callbacks = poll_funcs_init_tevent ( ctx ) ;
if ( ctx - > msg_callbacks = = NULL ) {
2014-06-10 18:57:05 +04:00
goto fail_nomem ;
2014-05-05 10:45:52 +04:00
}
ctx - > tevent_handle = poll_funcs_tevent_register (
2014-07-17 13:52:28 +04:00
ctx , ctx - > msg_callbacks , ev ) ;
2014-05-05 10:45:52 +04:00
if ( ctx - > tevent_handle = = NULL ) {
2014-06-10 18:57:05 +04:00
goto fail_nomem ;
2014-05-05 10:45:52 +04:00
}
2014-02-24 16:23:49 +04:00
2014-06-01 22:57:21 +04:00
unlink ( socket_address . sun_path ) ;
2014-02-24 16:23:49 +04:00
2014-09-14 19:52:07 +04:00
ret = unix_msg_init ( & socket_address , ctx - > msg_callbacks , 1024 ,
2014-02-24 16:23:49 +04:00
messaging_dgm_recv , ctx , & ctx - > dgm_ctx ) ;
if ( ret ! = 0 ) {
DEBUG ( 1 , ( " unix_msg_init failed: %s \n " , strerror ( ret ) ) ) ;
2014-07-17 15:23:46 +04:00
TALLOC_FREE ( ctx ) ;
2014-06-10 19:21:10 +04:00
return ret ;
2014-02-24 16:23:49 +04:00
}
talloc_set_destructor ( ctx , messaging_dgm_context_destructor ) ;
2014-07-20 16:51:47 +04:00
ctx - > have_dgm_context = & have_dgm_context ;
2014-09-10 18:13:18 +04:00
global_dgm_context = ctx ;
2014-06-10 19:21:10 +04:00
return 0 ;
2014-02-24 16:23:49 +04:00
fail_nomem :
2014-07-17 15:23:46 +04:00
TALLOC_FREE ( ctx ) ;
2014-06-10 19:21:10 +04:00
return ENOMEM ;
2014-02-24 16:23:49 +04:00
}
static int messaging_dgm_context_destructor ( struct messaging_dgm_context * c )
{
/*
* First delete the socket to avoid races . The lockfile is the
* indicator that we ' re still around .
*/
unix_msg_free ( c - > dgm_ctx ) ;
2014-07-25 15:03:11 +04:00
if ( getpid ( ) = = c - > pid ) {
2014-10-04 12:58:15 +04:00
struct sun_path_buf name ;
int ret ;
ret = snprintf ( name . buf , sizeof ( name . buf ) , " %s/%u " ,
c - > lockfile_dir . buf , ( unsigned ) c - > pid ) ;
if ( ret > = sizeof ( name . buf ) ) {
/*
* We ' ve checked the length when creating , so this
* should never happen
*/
abort ( ) ;
}
unlink ( name . buf ) ;
2014-02-24 16:23:49 +04:00
}
close ( c - > lockfile_fd ) ;
2014-07-20 16:51:47 +04:00
if ( c - > have_dgm_context ! = NULL ) {
* c - > have_dgm_context = false ;
}
2014-02-24 16:23:49 +04:00
return 0 ;
}
2014-09-10 18:13:18 +04:00
void messaging_dgm_destroy ( void )
{
TALLOC_FREE ( global_dgm_context ) ;
}
2014-05-17 17:16:02 +04:00
int messaging_dgm_send ( pid_t pid ,
const struct iovec * iov , int iovlen ,
const int * fds , size_t num_fds )
2014-02-24 16:23:49 +04:00
{
2014-09-10 18:13:18 +04:00
struct messaging_dgm_context * ctx = global_dgm_context ;
2014-06-01 22:57:21 +04:00
struct sockaddr_un dst ;
ssize_t dst_pathlen ;
2014-02-24 16:23:49 +04:00
int ret ;
2014-09-10 18:13:18 +04:00
if ( ctx = = NULL ) {
return ENOTCONN ;
}
2014-06-01 22:57:21 +04:00
dst = ( struct sockaddr_un ) { . sun_family = AF_UNIX } ;
2014-02-24 16:23:49 +04:00
2014-06-01 22:57:21 +04:00
dst_pathlen = snprintf ( dst . sun_path , sizeof ( dst . sun_path ) ,
2014-10-04 12:58:15 +04:00
" %s/%u " , ctx - > socket_dir . buf , ( unsigned ) pid ) ;
2014-06-01 22:57:21 +04:00
if ( dst_pathlen > = sizeof ( dst . sun_path ) ) {
2014-06-04 18:36:57 +04:00
return ENAMETOOLONG ;
2014-02-24 16:23:49 +04:00
}
2014-07-27 14:29:26 +04:00
DEBUG ( 10 , ( " %s: Sending message to %u \n " , __func__ , ( unsigned ) pid ) ) ;
2014-02-24 16:23:49 +04:00
2014-05-17 17:16:02 +04:00
ret = unix_msg_send ( ctx - > dgm_ctx , & dst , iov , iovlen , fds , num_fds ) ;
2014-02-24 16:23:49 +04:00
2014-06-04 18:36:57 +04:00
return ret ;
2014-02-24 16:23:49 +04:00
}
static void messaging_dgm_recv ( struct unix_msg_ctx * ctx ,
uint8_t * msg , size_t msg_len ,
2014-06-23 19:16:32 +04:00
int * fds , size_t num_fds ,
2014-02-24 16:23:49 +04:00
void * private_data )
{
struct messaging_dgm_context * dgm_ctx = talloc_get_type_abort (
private_data , struct messaging_dgm_context ) ;
2014-06-23 19:16:32 +04:00
2014-06-24 09:39:05 +04:00
dgm_ctx - > recv_cb ( msg , msg_len , fds , num_fds ,
dgm_ctx - > recv_cb_private_data ) ;
2014-02-24 16:23:49 +04:00
}
2014-09-10 18:13:18 +04:00
int messaging_dgm_cleanup ( pid_t pid )
2014-02-24 16:23:49 +04:00
{
2014-09-10 18:13:18 +04:00
struct messaging_dgm_context * ctx = global_dgm_context ;
2014-09-10 11:58:00 +04:00
struct sun_path_buf lockfile_name , socket_name ;
2014-10-04 12:58:15 +04:00
int fd , len , ret ;
2014-02-24 16:23:49 +04:00
struct flock lck = { } ;
2014-09-10 18:13:18 +04:00
if ( ctx = = NULL ) {
return ENOTCONN ;
}
2014-10-04 12:58:15 +04:00
len = snprintf ( socket_name . buf , sizeof ( socket_name . buf ) , " %s/%u " ,
ctx - > socket_dir . buf , ( unsigned ) pid ) ;
if ( len > = sizeof ( socket_name . buf ) ) {
return ENAMETOOLONG ;
2014-02-24 16:23:49 +04:00
}
2014-10-04 12:58:15 +04:00
len = snprintf ( lockfile_name . buf , sizeof ( lockfile_name . buf ) , " %s/%u " ,
ctx - > lockfile_dir . buf , ( unsigned ) pid ) ;
if ( len > = sizeof ( lockfile_name . buf ) ) {
return ENAMETOOLONG ;
}
2014-09-10 11:58:00 +04:00
fd = open ( lockfile_name . buf , O_NONBLOCK | O_WRONLY , 0 ) ;
2014-02-24 16:23:49 +04:00
if ( fd = = - 1 ) {
2014-06-04 18:42:46 +04:00
ret = errno ;
2014-08-18 15:58:05 +04:00
if ( ret ! = ENOENT ) {
DEBUG ( 10 , ( " %s: open(%s) failed: %s \n " , __func__ ,
2014-09-10 11:58:00 +04:00
lockfile_name . buf , strerror ( ret ) ) ) ;
2014-08-18 15:58:05 +04:00
}
2014-06-04 18:42:46 +04:00
return ret ;
2014-02-24 16:23:49 +04:00
}
lck . l_type = F_WRLCK ;
lck . l_whence = SEEK_SET ;
lck . l_start = 0 ;
lck . l_len = 0 ;
ret = fcntl ( fd , F_SETLK , & lck ) ;
if ( ret ! = 0 ) {
2014-06-04 18:42:46 +04:00
ret = errno ;
2014-10-04 12:58:15 +04:00
if ( ( ret ! = EACCES ) & & ( ret ! = EAGAIN ) ) {
DEBUG ( 10 , ( " %s: Could not get lock: %s \n " , __func__ ,
strerror ( ret ) ) ) ;
}
2014-02-24 16:23:49 +04:00
close ( fd ) ;
2014-06-04 18:42:46 +04:00
return ret ;
2014-02-24 16:23:49 +04:00
}
2014-10-04 12:58:15 +04:00
DEBUG ( 10 , ( " %s: Cleaning up : %s \n " , __func__ , strerror ( ret ) ) ) ;
2014-09-10 11:58:00 +04:00
( void ) unlink ( socket_name . buf ) ;
( void ) unlink ( lockfile_name . buf ) ;
2014-02-24 16:23:49 +04:00
( void ) close ( fd ) ;
2014-06-04 18:42:46 +04:00
return 0 ;
2014-02-24 16:23:49 +04:00
}
2014-04-11 00:07:11 +04:00
2014-09-10 18:13:18 +04:00
int messaging_dgm_wipe ( void )
2014-04-11 00:07:11 +04:00
{
2014-09-10 18:13:18 +04:00
struct messaging_dgm_context * ctx = global_dgm_context ;
2014-04-11 00:07:11 +04:00
DIR * msgdir ;
struct dirent * dp ;
pid_t our_pid = getpid ( ) ;
2014-06-04 18:47:05 +04:00
int ret ;
2014-04-11 00:07:11 +04:00
2014-09-10 18:13:18 +04:00
if ( ctx = = NULL ) {
return ENOTCONN ;
}
2014-04-11 00:07:11 +04:00
/*
* We scan the socket directory and not the lock directory . Otherwise
* we would race against messaging_dgm_lockfile_create ' s open ( O_CREAT )
* and fcntl ( SETLK ) .
*/
2014-10-04 12:58:15 +04:00
msgdir = opendir ( ctx - > socket_dir . buf ) ;
2014-04-11 00:07:11 +04:00
if ( msgdir = = NULL ) {
2014-10-04 12:58:15 +04:00
return errno ;
2014-04-11 00:07:11 +04:00
}
while ( ( dp = readdir ( msgdir ) ) ! = NULL ) {
unsigned long pid ;
pid = strtoul ( dp - > d_name , NULL , 10 ) ;
if ( pid = = 0 ) {
/*
* . and . . and other malformed entries
*/
continue ;
}
if ( pid = = our_pid ) {
/*
* fcntl ( F_GETLK ) will succeed for ourselves , we hold
* that lock ourselves .
*/
continue ;
}
2014-09-10 18:13:18 +04:00
ret = messaging_dgm_cleanup ( pid ) ;
2014-04-11 00:07:11 +04:00
DEBUG ( 10 , ( " messaging_dgm_cleanup(%lu) returned %s \n " ,
2014-06-04 18:42:46 +04:00
pid , ret ? strerror ( ret ) : " ok " ) ) ;
2014-04-11 00:07:11 +04:00
}
closedir ( msgdir ) ;
2014-06-04 18:47:05 +04:00
return 0 ;
2014-04-11 00:07:11 +04:00
}
2014-05-06 11:11:17 +04:00
void * messaging_dgm_register_tevent_context ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev )
{
2014-09-10 18:13:18 +04:00
struct messaging_dgm_context * ctx = global_dgm_context ;
if ( ctx = = NULL ) {
return NULL ;
}
2014-05-06 11:11:17 +04:00
return poll_funcs_tevent_register ( mem_ctx , ctx - > msg_callbacks , ev ) ;
}