2004-10-17 05:07:07 +00:00
/*
Unix SMB / CIFS implementation .
unix domain socket functions
Copyright ( C ) Stefan Metzmacher 2004
2005-01-19 03:20:20 +00:00
Copyright ( C ) Andrew Tridgell 2004 - 2005
2004-10-17 05:07:07 +00: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 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2004-10-17 05:07:07 +00: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 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-10-17 05:07:07 +00:00
*/
# include "includes.h"
2005-02-10 06:59:29 +00:00
# include "lib/socket/socket.h"
2004-11-02 12:43:25 +00:00
# include "system/network.h"
2005-02-10 05:09:35 +00:00
# include "system/filesys.h"
2004-10-17 05:07:07 +00:00
2004-10-17 13:21:24 +00:00
/*
approximate errno mapping
*/
static NTSTATUS unixdom_error ( int ernum )
{
2004-10-27 03:15:42 +00:00
return map_nt_error_from_unix ( ernum ) ;
2004-10-17 13:21:24 +00:00
}
2004-10-17 05:07:07 +00:00
static NTSTATUS unixdom_init ( struct socket_context * sock )
{
2005-05-01 18:49:43 +00:00
int type ;
switch ( sock - > type ) {
case SOCKET_TYPE_STREAM :
type = SOCK_STREAM ;
break ;
case SOCKET_TYPE_DGRAM :
type = SOCK_DGRAM ;
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
}
sock - > fd = socket ( PF_UNIX , type , 0 ) ;
2004-10-17 05:07:07 +00:00
if ( sock - > fd = = - 1 ) {
2005-05-01 18:49:43 +00:00
return map_nt_error_from_unix ( errno ) ;
2004-10-17 05:07:07 +00:00
}
2004-10-17 10:04:49 +00:00
sock - > private_data = NULL ;
2004-10-17 05:07:07 +00:00
2005-08-28 02:37:38 +00:00
sock - > backend_name = " unix " ;
2004-10-17 05:07:07 +00:00
return NT_STATUS_OK ;
}
static void unixdom_close ( struct socket_context * sock )
{
close ( sock - > fd ) ;
}
2005-01-15 10:28:08 +00:00
static NTSTATUS unixdom_connect_complete ( struct socket_context * sock , uint32_t flags )
{
int error = 0 , ret ;
socklen_t len = sizeof ( error ) ;
/* check for any errors that may have occurred - this is needed
for non - blocking connect */
ret = getsockopt ( sock - > fd , SOL_SOCKET , SO_ERROR , & error , & len ) ;
if ( ret = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
if ( error ! = 0 ) {
return map_nt_error_from_unix ( error ) ;
}
if ( ! ( flags & SOCKET_FLAG_BLOCK ) ) {
2007-10-05 18:03:01 +00:00
ret = set_blocking ( sock - > fd , false ) ;
2005-01-15 10:28:08 +00:00
if ( ret = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
}
sock - > state = SOCKET_STATE_CLIENT_CONNECTED ;
return NT_STATUS_OK ;
}
2004-10-17 05:07:07 +00:00
static NTSTATUS unixdom_connect ( struct socket_context * sock ,
2006-01-09 22:12:53 +00:00
const struct socket_address * my_address ,
const struct socket_address * srv_address ,
2004-10-17 05:07:07 +00:00
uint32_t flags )
{
int ret ;
2006-01-09 22:12:53 +00:00
if ( srv_address - > sockaddr ) {
ret = connect ( sock - > fd , srv_address - > sockaddr , srv_address - > sockaddrlen ) ;
} else {
struct sockaddr_un srv_addr ;
if ( strlen ( srv_address - > addr ) + 1 > sizeof ( srv_addr . sun_path ) ) {
return NT_STATUS_OBJECT_PATH_INVALID ;
}
ZERO_STRUCT ( srv_addr ) ;
srv_addr . sun_family = AF_UNIX ;
strncpy ( srv_addr . sun_path , srv_address - > addr , sizeof ( srv_addr . sun_path ) ) ;
2004-10-17 05:07:07 +00:00
2006-01-09 22:12:53 +00:00
ret = connect ( sock - > fd , ( const struct sockaddr * ) & srv_addr , sizeof ( srv_addr ) ) ;
}
2004-10-17 05:07:07 +00:00
if ( ret = = - 1 ) {
2004-10-17 13:21:24 +00:00
return unixdom_error ( errno ) ;
2004-10-17 05:07:07 +00:00
}
2005-01-15 10:28:08 +00:00
return unixdom_connect_complete ( sock , flags ) ;
2004-10-17 05:07:07 +00:00
}
static NTSTATUS unixdom_listen ( struct socket_context * sock ,
2006-01-09 22:12:53 +00:00
const struct socket_address * my_address ,
2004-10-17 05:07:07 +00:00
int queue_size , uint32_t flags )
{
struct sockaddr_un my_addr ;
int ret ;
2004-10-17 10:04:49 +00:00
/* delete if it already exists */
2006-01-09 22:12:53 +00:00
if ( my_address - > addr ) {
unlink ( my_address - > addr ) ;
}
2004-10-17 05:07:07 +00:00
2006-03-13 06:57:11 +00:00
if ( my_address - > sockaddr ) {
2006-01-09 22:12:53 +00:00
ret = bind ( sock - > fd , ( struct sockaddr * ) & my_addr , sizeof ( my_addr ) ) ;
2006-03-13 06:57:11 +00:00
} else if ( my_address - > addr = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
2006-01-09 22:12:53 +00:00
} else {
if ( strlen ( my_address - > addr ) + 1 > sizeof ( my_addr . sun_path ) ) {
return NT_STATUS_OBJECT_PATH_INVALID ;
}
ZERO_STRUCT ( my_addr ) ;
my_addr . sun_family = AF_UNIX ;
strncpy ( my_addr . sun_path , my_address - > addr , sizeof ( my_addr . sun_path ) ) ;
ret = bind ( sock - > fd , ( struct sockaddr * ) & my_addr , sizeof ( my_addr ) ) ;
}
2004-10-17 05:07:07 +00:00
if ( ret = = - 1 ) {
2004-10-17 13:21:24 +00:00
return unixdom_error ( errno ) ;
2004-10-17 05:07:07 +00:00
}
2005-05-01 18:49:43 +00:00
if ( sock - > type = = SOCKET_TYPE_STREAM ) {
ret = listen ( sock - > fd , queue_size ) ;
if ( ret = = - 1 ) {
return unixdom_error ( errno ) ;
}
2004-10-17 05:07:07 +00:00
}
if ( ! ( flags & SOCKET_FLAG_BLOCK ) ) {
2007-10-05 18:03:01 +00:00
ret = set_blocking ( sock - > fd , false ) ;
2004-10-17 05:07:07 +00:00
if ( ret = = - 1 ) {
2004-10-17 13:21:24 +00:00
return unixdom_error ( errno ) ;
2004-10-17 05:07:07 +00:00
}
}
sock - > state = SOCKET_STATE_SERVER_LISTEN ;
2006-01-09 22:12:53 +00:00
sock - > private_data = ( void * ) talloc_strdup ( sock , my_address - > addr ) ;
2004-10-17 05:07:07 +00:00
return NT_STATUS_OK ;
}
static NTSTATUS unixdom_accept ( struct socket_context * sock ,
2004-10-28 07:55:33 +00:00
struct socket_context * * new_sock )
2004-10-17 05:07:07 +00:00
{
struct sockaddr_un cli_addr ;
socklen_t cli_addr_len = sizeof ( cli_addr ) ;
int new_fd ;
2005-05-01 18:49:43 +00:00
if ( sock - > type ! = SOCKET_TYPE_STREAM ) {
return NT_STATUS_INVALID_PARAMETER ;
}
2004-10-17 05:07:07 +00:00
new_fd = accept ( sock - > fd , ( struct sockaddr * ) & cli_addr , & cli_addr_len ) ;
if ( new_fd = = - 1 ) {
2004-10-17 13:21:24 +00:00
return unixdom_error ( errno ) ;
2004-10-17 05:07:07 +00:00
}
2004-10-28 07:55:33 +00:00
if ( ! ( sock - > flags & SOCKET_FLAG_BLOCK ) ) {
2007-10-05 18:03:01 +00:00
int ret = set_blocking ( new_fd , false ) ;
2004-10-28 07:34:11 +00:00
if ( ret = = - 1 ) {
close ( new_fd ) ;
return map_nt_error_from_unix ( errno ) ;
}
}
2005-01-27 07:08:20 +00:00
( * new_sock ) = talloc ( NULL , struct socket_context ) ;
2004-10-17 05:07:07 +00:00
if ( ! ( * new_sock ) ) {
close ( new_fd ) ;
return NT_STATUS_NO_MEMORY ;
}
/* copy the socket_context */
( * new_sock ) - > type = sock - > type ;
( * new_sock ) - > state = SOCKET_STATE_SERVER_CONNECTED ;
2004-10-28 07:55:33 +00:00
( * new_sock ) - > flags = sock - > flags ;
2004-10-17 05:07:07 +00:00
( * new_sock ) - > fd = new_fd ;
( * new_sock ) - > private_data = NULL ;
( * new_sock ) - > ops = sock - > ops ;
2005-08-28 02:37:49 +00:00
( * new_sock ) - > backend_name = sock - > backend_name ;
2004-10-17 05:07:07 +00:00
return NT_STATUS_OK ;
}
2004-10-28 04:00:43 +00:00
static NTSTATUS unixdom_recv ( struct socket_context * sock , void * buf ,
2006-04-30 05:58:31 +00:00
size_t wantlen , size_t * nread )
2004-10-17 05:07:07 +00:00
{
ssize_t gotlen ;
2004-10-28 04:00:43 +00:00
* nread = 0 ;
2006-04-30 05:58:31 +00:00
gotlen = recv ( sock - > fd , buf , wantlen , 0 ) ;
2004-10-17 05:07:07 +00:00
if ( gotlen = = 0 ) {
return NT_STATUS_END_OF_FILE ;
} else if ( gotlen = = - 1 ) {
2004-10-28 04:00:43 +00:00
return unixdom_error ( errno ) ;
2004-10-17 05:07:07 +00:00
}
2004-10-28 04:00:43 +00:00
* nread = gotlen ;
2004-10-17 05:07:07 +00:00
return NT_STATUS_OK ;
}
2004-10-28 04:00:43 +00:00
static NTSTATUS unixdom_send ( struct socket_context * sock ,
2006-04-30 05:58:31 +00:00
const DATA_BLOB * blob , size_t * sendlen )
2004-10-17 05:07:07 +00:00
{
ssize_t len ;
2004-10-17 13:21:24 +00:00
* sendlen = 0 ;
2006-04-30 05:58:31 +00:00
len = send ( sock - > fd , blob - > data , blob - > length , 0 ) ;
2004-10-17 05:07:07 +00:00
if ( len = = - 1 ) {
2004-10-17 13:21:24 +00:00
return unixdom_error ( errno ) ;
2004-10-17 05:07:07 +00:00
}
* sendlen = len ;
return NT_STATUS_OK ;
}
2005-06-03 04:19:32 +00:00
static NTSTATUS unixdom_sendto ( struct socket_context * sock ,
2006-04-30 05:58:31 +00:00
const DATA_BLOB * blob , size_t * sendlen ,
2006-01-09 22:12:53 +00:00
const struct socket_address * dest )
2005-06-03 04:19:32 +00:00
{
ssize_t len ;
* sendlen = 0 ;
2006-01-09 22:12:53 +00:00
if ( dest - > sockaddr ) {
2006-04-30 05:58:31 +00:00
len = sendto ( sock - > fd , blob - > data , blob - > length , 0 ,
2006-01-09 22:12:53 +00:00
dest - > sockaddr , dest - > sockaddrlen ) ;
} else {
struct sockaddr_un srv_addr ;
if ( strlen ( dest - > addr ) + 1 > sizeof ( srv_addr . sun_path ) ) {
return NT_STATUS_OBJECT_PATH_INVALID ;
}
ZERO_STRUCT ( srv_addr ) ;
srv_addr . sun_family = AF_UNIX ;
strncpy ( srv_addr . sun_path , dest - > addr , sizeof ( srv_addr . sun_path ) ) ;
2006-04-30 05:58:31 +00:00
len = sendto ( sock - > fd , blob - > data , blob - > length , 0 ,
2006-01-09 22:12:53 +00:00
( struct sockaddr * ) & srv_addr , sizeof ( srv_addr ) ) ;
}
2005-06-03 04:19:32 +00:00
if ( len = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
}
* sendlen = len ;
return NT_STATUS_OK ;
}
2004-10-17 05:07:07 +00:00
static NTSTATUS unixdom_set_option ( struct socket_context * sock ,
const char * option , const char * val )
{
return NT_STATUS_OK ;
}
static char * unixdom_get_peer_name ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
{
return talloc_strdup ( mem_ctx , " LOCAL/unixdom " ) ;
}
2006-01-09 22:12:53 +00:00
static struct socket_address * unixdom_get_peer_addr ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2004-10-17 05:07:07 +00:00
{
2006-01-09 22:12:53 +00:00
struct sockaddr_in * peer_addr ;
socklen_t len = sizeof ( * peer_addr ) ;
struct socket_address * peer ;
int ret ;
2004-10-17 05:07:07 +00:00
2006-01-09 22:12:53 +00:00
peer = talloc ( mem_ctx , struct socket_address ) ;
if ( ! peer ) {
return NULL ;
}
peer - > family = sock - > backend_name ;
peer_addr = talloc ( peer , struct sockaddr_in ) ;
if ( ! peer_addr ) {
talloc_free ( peer ) ;
return NULL ;
}
2004-10-17 05:07:07 +00:00
2006-01-09 22:12:53 +00:00
peer - > sockaddr = ( struct sockaddr * ) peer_addr ;
ret = getpeername ( sock - > fd , peer - > sockaddr , & len ) ;
if ( ret = = - 1 ) {
talloc_free ( peer ) ;
return NULL ;
}
peer - > sockaddrlen = len ;
peer - > port = 0 ;
peer - > addr = talloc_strdup ( peer , " LOCAL/unixdom " ) ;
if ( ! peer - > addr ) {
talloc_free ( peer ) ;
return NULL ;
}
return peer ;
2004-10-17 05:07:07 +00:00
}
2006-01-09 22:12:53 +00:00
static struct socket_address * unixdom_get_my_addr ( struct socket_context * sock , TALLOC_CTX * mem_ctx )
2004-10-17 05:07:07 +00:00
{
2006-01-09 22:12:53 +00:00
struct sockaddr_in * local_addr ;
socklen_t len = sizeof ( * local_addr ) ;
struct socket_address * local ;
int ret ;
local = talloc ( mem_ctx , struct socket_address ) ;
if ( ! local ) {
return NULL ;
}
local - > family = sock - > backend_name ;
local_addr = talloc ( local , struct sockaddr_in ) ;
if ( ! local_addr ) {
talloc_free ( local ) ;
return NULL ;
}
local - > sockaddr = ( struct sockaddr * ) local_addr ;
ret = getsockname ( sock - > fd , local - > sockaddr , & len ) ;
if ( ret = = - 1 ) {
talloc_free ( local ) ;
return NULL ;
}
local - > sockaddrlen = len ;
local - > port = 0 ;
local - > addr = talloc_strdup ( local , " LOCAL/unixdom " ) ;
if ( ! local - > addr ) {
talloc_free ( local ) ;
return NULL ;
}
return local ;
2004-10-17 05:07:07 +00:00
}
static int unixdom_get_fd ( struct socket_context * sock )
{
return sock - > fd ;
}
2005-06-03 13:20:08 +00:00
static NTSTATUS unixdom_pending ( struct socket_context * sock , size_t * npending )
{
int value = 0 ;
if ( ioctl ( sock - > fd , FIONREAD , & value ) = = 0 ) {
* npending = value ;
return NT_STATUS_OK ;
}
return map_nt_error_from_unix ( errno ) ;
}
2004-10-17 05:07:07 +00:00
static const struct socket_ops unixdom_ops = {
2004-11-02 02:01:04 +00:00
. name = " unix " ,
. fn_init = unixdom_init ,
. fn_connect = unixdom_connect ,
2005-01-15 10:28:08 +00:00
. fn_connect_complete = unixdom_connect_complete ,
2004-11-02 02:01:04 +00:00
. fn_listen = unixdom_listen ,
. fn_accept = unixdom_accept ,
. fn_recv = unixdom_recv ,
. fn_send = unixdom_send ,
2005-06-03 04:19:32 +00:00
. fn_sendto = unixdom_sendto ,
2004-11-02 02:01:04 +00:00
. fn_close = unixdom_close ,
2005-06-03 13:20:08 +00:00
. fn_pending = unixdom_pending ,
2004-11-02 02:01:04 +00:00
. fn_set_option = unixdom_set_option ,
. fn_get_peer_name = unixdom_get_peer_name ,
. fn_get_peer_addr = unixdom_get_peer_addr ,
. fn_get_my_addr = unixdom_get_my_addr ,
. fn_get_fd = unixdom_get_fd
2004-10-17 05:07:07 +00:00
} ;
2008-02-20 19:40:20 +01:00
_PUBLIC_ const struct socket_ops * socket_unixdom_ops ( enum socket_type type )
2004-10-17 05:07:07 +00:00
{
return & unixdom_ops ;
}