2007-04-24 02:17:06 +04:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) James Peach 2007
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
2007-04-24 02:17:06 +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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "smb_launchd.h"
extern pstring user_socket_options ;
static int init_sockets_smbd ( const char * smb_ports , int listenset [ FD_SETSIZE ] )
{
int num_interfaces = iface_count ( ) ;
char * ports ;
int num_sockets = 0 ;
int i , s ;
/* use a reasonable default set of ports - listing on 445 and 139 */
if ( ! smb_ports ) {
ports = lp_smb_ports ( ) ;
if ( ! ports | | ! * ports ) {
ports = smb_xstrdup ( SMB_PORTS ) ;
} else {
ports = smb_xstrdup ( ports ) ;
}
} else {
ports = smb_xstrdup ( smb_ports ) ;
}
if ( lp_interfaces ( ) & & lp_bind_interfaces_only ( ) ) {
/* We have been given an interfaces line, and been
told to only bind to those interfaces . Create a
socket per interface and bind to only these .
*/
/* Now open a listen socket for each of the
interfaces . */
for ( i = 0 ; i < num_interfaces ; i + + ) {
struct in_addr * ifip = iface_n_ip ( i ) ;
fstring tok ;
const char * ptr ;
if ( ifip = = NULL ) {
DEBUG ( 0 , ( " init_sockets_smbd: interface %d has NULL IP address ! \n " , i ) ) ;
continue ;
}
for ( ptr = ports ; next_token ( & ptr , tok , " \t , " , sizeof ( tok ) ) ; ) {
unsigned port = atoi ( tok ) ;
2007-07-03 17:11:56 +04:00
if ( port = = 0 | | port > 0xffff ) {
2007-04-24 02:17:06 +04:00
continue ;
}
s = listenset [ num_sockets ] = open_socket_in ( SOCK_STREAM , port , 0 , ifip - > s_addr , True ) ;
if ( s = = - 1 )
return 0 ;
/* ready to listen */
set_socket_options ( s , " SO_KEEPALIVE " ) ;
set_socket_options ( s , user_socket_options ) ;
/* Set server socket to non-blocking for the accept. */
set_blocking ( s , False ) ;
if ( listen ( s , SMBD_LISTEN_BACKLOG ) = = - 1 ) {
DEBUG ( 0 , ( " listen: %s \n " , strerror ( errno ) ) ) ;
close ( s ) ;
return 0 ;
}
num_sockets + + ;
if ( num_sockets > = FD_SETSIZE ) {
DEBUG ( 0 , ( " init_sockets_smbd: Too many sockets to bind to \n " ) ) ;
return 0 ;
}
}
}
} else {
/* Just bind to 0.0.0.0 - accept connections
from anywhere . */
fstring tok ;
const char * ptr ;
num_interfaces = 1 ;
for ( ptr = ports ; next_token ( & ptr , tok , " \t , " , sizeof ( tok ) ) ; ) {
unsigned port = atoi ( tok ) ;
2007-07-03 17:11:56 +04:00
if ( port = = 0 | | port > 0xffff ) continue ;
2007-04-24 02:17:06 +04:00
/* open an incoming socket */
s = open_socket_in ( SOCK_STREAM , port , 0 ,
interpret_addr ( lp_socket_address ( ) ) , True ) ;
if ( s = = - 1 )
return 0 ;
/* ready to listen */
set_socket_options ( s , " SO_KEEPALIVE " ) ;
set_socket_options ( s , user_socket_options ) ;
/* Set server socket to non-blocking for the accept. */
set_blocking ( s , False ) ;
if ( listen ( s , SMBD_LISTEN_BACKLOG ) = = - 1 ) {
DEBUG ( 0 , ( " init_sockets_smbd: listen: %s \n " ,
strerror ( errno ) ) ) ;
close ( s ) ;
return 0 ;
}
listenset [ num_sockets ] = s ;
num_sockets + + ;
if ( num_sockets > = FD_SETSIZE ) {
DEBUG ( 0 , ( " init_sockets_smbd: Too many sockets to bind to \n " ) ) ;
return 0 ;
}
}
}
SAFE_FREE ( ports ) ;
return num_sockets ;
}
static int init_sockets_launchd ( const struct smb_launch_info * linfo ,
const char * smb_ports ,
int listenset [ FD_SETSIZE ] )
{
int num_sockets ;
int i ;
/* The launchd service configuration does not have to provide sockets,
* even though it ' s basically useless without it .
*/
if ( ! linfo - > num_sockets ) {
return init_sockets_smbd ( smb_ports , listenset ) ;
}
/* Make sure we don't get more sockets than we can handle. */
num_sockets = MIN ( FD_SETSIZE , linfo - > num_sockets ) ;
memcpy ( listenset , linfo - > socket_list , num_sockets * sizeof ( int ) ) ;
/* Get the sockets ready. This could be hoisted into
* open_sockets_smbd ( ) , but the order of socket operations might
* matter for some platforms , so this approach seems less risky .
* - - jpeach
*/
for ( i = 0 ; i < num_sockets ; + + i ) {
set_socket_options ( listenset [ i ] , " SO_KEEPALIVE " ) ;
set_socket_options ( listenset [ i ] , user_socket_options ) ;
/* Set server socket to non-blocking for the accept. */
set_blocking ( listenset [ i ] , False ) ;
}
return num_sockets ;
}
/* This function is responsible for opening (or retrieving) all the sockets we
* smbd will be listening on . It should apply all the configured socket options
* and return the number of valid sockets in listenset .
*/
int smbd_sockinit ( const char * cmdline_ports , int listenset [ FD_SETSIZE ] ,
struct timeval * idle )
{
int num_sockets ;
struct smb_launch_info linfo ;
ZERO_STRUCTP ( idle ) ;
if ( smb_launchd_checkin ( & linfo ) ) {
/* We are running under launchd and launchd has
* opened some sockets for us .
*/
num_sockets = init_sockets_launchd ( & linfo ,
cmdline_ports ,
listenset ) ;
idle - > tv_sec = linfo . idle_timeout_secs ;
smb_launchd_checkout ( & linfo ) ;
} else {
num_sockets = init_sockets_smbd ( cmdline_ports ,
listenset ) ;
}
return num_sockets ;
}