1998-08-30 19:58:17 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-30 19:58:17 +04:00
NBT netbios routines and daemon - version 2
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1994 - 1998
Copyright ( C ) Jeremy Allison 1994 - 1998
2011-05-28 22:24:01 +04:00
1998-08-30 19:58:17 +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
1998-08-30 19:58:17 +04:00
( at your option ) any later version .
2011-05-28 22:24:01 +04:00
1998-08-30 19:58:17 +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 .
2011-05-28 22:24:01 +04:00
1998-08-30 19:58:17 +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/>.
1998-08-30 19:58:17 +04:00
*/
/* this file handles asynchronous browse synchronisation requests. The
requests are done by forking and putting the result in a file in the
locks directory . We do it this way because we don ' t want nmbd to be
blocked waiting for some server to respond on a TCP connection . This
also allows us to have more than 1 sync going at once ( tridge ) */
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2010-08-03 00:48:16 +04:00
# include "../librpc/gen_ndr/svcctl.h"
2010-08-18 17:22:09 +04:00
# include "nmbd/nmbd.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-02-24 12:46:55 +03:00
# include "libsmb/clirap.h"
2012-05-20 19:54:29 +04:00
# include "../libcli/smb/smbXcli_base.h"
1998-08-30 19:58:17 +04:00
struct sync_record {
struct sync_record * next , * prev ;
2004-03-16 00:45:45 +03:00
unstring workgroup ;
unstring server ;
2007-11-20 02:15:09 +03:00
char * fname ;
1998-08-30 19:58:17 +04:00
struct in_addr ip ;
1999-12-13 16:27:58 +03:00
pid_t pid ;
1998-08-30 19:58:17 +04:00
} ;
/* a linked list of current sync connections */
static struct sync_record * syncs ;
2016-11-26 11:50:33 +03:00
static FILE * fp ;
1998-08-30 19:58:17 +04:00
/*******************************************************************
This is the NetServerEnum callback .
2000-10-07 05:15:07 +04:00
Note sname and comment are in UNIX codepage format .
1998-08-30 19:58:17 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2015-04-30 06:14:34 +03:00
static void callback ( const char * sname , uint32_t stype ,
2001-01-04 14:35:55 +03:00
const char * comment , void * state )
1998-08-30 19:58:17 +04:00
{
2016-11-26 11:50:33 +03:00
fprintf ( fp , " \" %s \" %08X \" %s \" \n " , sname , stype , comment ) ;
1998-08-30 19:58:17 +04:00
}
/*******************************************************************
Synchronise browse lists with another browse server .
Log in on the remote server ' s SMB port to their IPC $ service ,
do a NetServerEnum and record the results in fname
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
1998-08-30 19:58:17 +04:00
static void sync_child ( char * name , int nm_type ,
char * workgroup ,
2007-10-19 04:40:25 +04:00
struct in_addr ip , bool local , bool servers ,
1998-08-30 19:58:17 +04:00
char * fname )
{
2000-10-07 05:15:07 +04:00
fstring unix_workgroup ;
2006-07-11 22:01:26 +04:00
struct cli_state * cli ;
2015-04-30 06:14:34 +03:00
uint32_t local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0 ;
2007-10-25 01:16:54 +04:00
struct sockaddr_storage ss ;
2007-06-20 21:38:42 +04:00
NTSTATUS status ;
1998-08-30 19:58:17 +04:00
2002-09-25 19:19:00 +04:00
/* W2K DMB's return empty browse lists on port 445. Use 139.
* Patch from Andy Levine andyl @ epicrealm . com .
*/
2007-10-25 01:16:54 +04:00
in_addr_to_sockaddr_storage ( & ss , ip ) ;
1998-09-26 01:01:52 +04:00
2012-02-15 07:51:35 +04:00
status = cli_connect_nb ( name , & ss , NBT_SMB_PORT , nm_type ,
2011-11-02 21:41:50 +04:00
get_local_machine_name ( ) , SMB_SIGNING_DEFAULT ,
0 , & cli ) ;
2011-05-29 15:38:20 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
1998-08-30 19:58:17 +04:00
return ;
}
2012-05-20 19:54:29 +04:00
status = smbXcli_negprot ( cli - > conn , cli - > timeout , PROTOCOL_CORE ,
PROTOCOL_NT1 ) ;
2008-09-11 20:57:49 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
1998-08-30 19:58:17 +04:00
return ;
}
2016-10-28 13:15:20 +03:00
status = cli_session_setup_anon ( cli ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
1998-08-30 19:58:17 +04:00
return ;
}
2016-12-08 09:13:57 +03:00
if ( ! NT_STATUS_IS_OK ( cli_tree_connect ( cli , " IPC$ " , " IPC " , NULL ) ) ) {
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
1998-08-30 19:58:17 +04:00
return ;
}
2000-10-07 05:15:07 +04:00
/* All the cli_XX functions take UNIX character set. */
2006-07-11 22:01:26 +04:00
fstrcpy ( unix_workgroup , cli - > server_domain ? cli - > server_domain : workgroup ) ;
2000-10-07 05:15:07 +04:00
1998-08-30 19:58:17 +04:00
/* Fetch a workgroup list. */
2006-07-11 22:01:26 +04:00
cli_NetServerEnum ( cli , unix_workgroup ,
2001-01-04 14:35:55 +03:00
local_type | SV_TYPE_DOMAIN_ENUM ,
callback , NULL ) ;
2011-05-28 22:24:01 +04:00
1998-08-30 19:58:17 +04:00
/* Now fetch a server list. */
if ( servers ) {
2000-10-07 05:15:07 +04:00
fstrcpy ( unix_workgroup , workgroup ) ;
2006-07-11 22:01:26 +04:00
cli_NetServerEnum ( cli , unix_workgroup ,
1998-08-30 19:58:17 +04:00
local ? SV_TYPE_LOCAL_LIST_ONLY : SV_TYPE_ALL ,
2001-01-04 14:35:55 +03:00
callback , NULL ) ;
1998-08-30 19:58:17 +04:00
}
2011-05-28 22:24:01 +04:00
2006-07-11 22:01:26 +04:00
cli_shutdown ( cli ) ;
1998-08-30 19:58:17 +04:00
}
/*******************************************************************
initialise a browse sync with another browse server . Log in on the
remote server ' s SMB port to their IPC $ service , do a NetServerEnum
and record the results
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
1998-08-30 19:58:17 +04:00
void sync_browse_lists ( struct work_record * work ,
char * name , int nm_type ,
2007-10-19 04:40:25 +04:00
struct in_addr ip , bool local , bool servers )
1998-08-30 19:58:17 +04:00
{
struct sync_record * s ;
static int counter ;
2016-11-26 11:50:33 +03:00
int fd ;
1998-08-30 19:58:17 +04:00
/* Check we're not trying to sync with ourselves. This can
happen if we are a domain * and * a local master browser . */
2007-10-11 05:25:16 +04:00
if ( ismyip_v4 ( ip ) ) {
2001-09-05 22:43:55 +04:00
done :
1998-08-30 19:58:17 +04:00
return ;
}
2004-12-07 21:25:53 +03:00
s = SMB_MALLOC_P ( struct sync_record ) ;
2001-09-05 22:43:55 +04:00
if ( ! s ) goto done ;
1998-08-30 19:58:17 +04:00
ZERO_STRUCTP ( s ) ;
2007-11-20 02:15:09 +03:00
2004-03-16 00:45:45 +03:00
unstrcpy ( s - > workgroup , work - > work_group ) ;
unstrcpy ( s - > server , name ) ;
1998-08-30 19:58:17 +04:00
s - > ip = ip ;
2014-02-03 06:46:08 +04:00
if ( asprintf ( & s - > fname , " %s/sync.%d " , lp_lock_directory ( ) , counter + + ) < 0 ) {
2007-11-20 02:15:09 +03:00
SAFE_FREE ( s ) ;
goto done ;
}
/* Safe to use as 0 means no size change. */
1999-12-13 16:27:58 +03:00
all_string_sub ( s - > fname , " // " , " / " , 0 ) ;
2007-11-20 02:15:09 +03:00
1998-08-30 19:58:17 +04:00
DLIST_ADD ( syncs , s ) ;
/* the parent forks and returns, leaving the child to do the
2014-11-05 15:10:49 +03:00
actual sync */
1998-08-30 19:58:17 +04:00
CatchChild ( ) ;
2012-03-24 23:17:08 +04:00
if ( ( s - > pid = fork ( ) ) ) return ;
1998-08-30 19:58:17 +04:00
1998-08-31 07:11:42 +04:00
BlockSignals ( False , SIGTERM ) ;
1998-08-30 19:58:17 +04:00
DEBUG ( 2 , ( " Initiating browse sync for %s to %s(%s) \n " ,
work - > work_group , name , inet_ntoa ( ip ) ) ) ;
2016-11-26 11:50:33 +03:00
fd = open ( s - > fname , O_WRONLY | O_CREAT | O_TRUNC , 0644 ) ;
if ( fd = = - 1 ) {
_exit ( 1 ) ;
}
fp = fdopen ( fd , " w " ) ;
2001-09-05 22:43:55 +04:00
if ( ! fp ) {
2007-11-20 02:15:09 +03:00
_exit ( 1 ) ;
2001-09-05 22:43:55 +04:00
}
2016-11-26 11:50:33 +03:00
fd = - 1 ;
1998-08-30 19:58:17 +04:00
sync_child ( name , nm_type , work - > work_group , ip , local , servers ,
s - > fname ) ;
2016-11-26 11:50:33 +03:00
fclose ( fp ) ;
1998-08-30 19:58:17 +04:00
_exit ( 0 ) ;
}
/**********************************************************************
2003-08-27 05:25:01 +04:00
Handle one line from a completed sync file .
1998-08-30 19:58:17 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2007-12-08 04:32:32 +03:00
static void complete_one ( struct sync_record * s ,
2015-04-30 06:14:34 +03:00
char * sname , uint32_t stype , char * comment )
1998-08-30 19:58:17 +04:00
{
struct work_record * work ;
struct server_record * servrec ;
stype & = ~ SV_TYPE_LOCAL_LIST_ONLY ;
if ( stype & SV_TYPE_DOMAIN_ENUM ) {
/* See if we can find the workgroup on this subnet. */
if ( ( work = find_workgroup_on_subnet ( unicast_subnet , sname ) ) ) {
/* We already know about this workgroup -
update the ttl . */
update_workgroup_ttl ( work , lp_max_ttl ( ) ) ;
} else {
/* Create the workgroup on the subnet. */
work = create_workgroup_on_subnet ( unicast_subnet ,
sname , lp_max_ttl ( ) ) ;
if ( work ) {
/* remember who the master is */
2004-03-16 00:45:45 +03:00
unstrcpy ( work - > local_master_browser_name , comment ) ;
1998-08-30 19:58:17 +04:00
}
}
return ;
}
work = find_workgroup_on_subnet ( unicast_subnet , s - > workgroup ) ;
if ( ! work ) {
DEBUG ( 3 , ( " workgroup %s doesn't exist on unicast subnet? \n " ,
s - > workgroup ) ) ;
return ;
}
if ( ( servrec = find_server_in_workgroup ( work , sname ) ) ) {
/* Check that this is not a locally known
server - if so ignore the entry . */
if ( ! ( servrec - > serv . type & SV_TYPE_LOCAL_LIST_ONLY ) ) {
/* We already know about this server - update
the ttl . */
update_server_ttl ( servrec , lp_max_ttl ( ) ) ;
/* Update the type. */
servrec - > serv . type = stype ;
}
return ;
}
/* Create the server in the workgroup. */
create_server_on_workgroup ( work , sname , stype , lp_max_ttl ( ) , comment ) ;
}
2007-11-20 02:15:09 +03:00
1998-08-30 19:58:17 +04:00
/**********************************************************************
2003-08-27 05:25:01 +04:00
Read the completed sync info .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-30 19:58:17 +04:00
static void complete_sync ( struct sync_record * s )
{
2016-11-26 11:50:33 +03:00
FILE * f ;
2007-12-08 04:32:32 +03:00
char * server ;
char * type_str ;
1998-08-30 19:58:17 +04:00
unsigned type ;
2007-12-08 04:32:32 +03:00
char * comment ;
2007-11-20 02:15:09 +03:00
char line [ 1024 ] ;
2002-11-13 02:20:50 +03:00
const char * ptr ;
1998-08-30 19:58:17 +04:00
int count = 0 ;
2016-11-26 11:50:33 +03:00
f = fopen ( s - > fname , " r " ) ;
1998-09-17 12:35:07 +04:00
2003-08-27 05:25:01 +04:00
if ( ! f )
return ;
2007-11-20 02:15:09 +03:00
2016-11-26 11:50:33 +03:00
while ( ! feof ( f ) ) {
2007-12-08 04:32:32 +03:00
TALLOC_CTX * frame = NULL ;
2007-11-20 02:15:09 +03:00
2016-11-26 11:50:33 +03:00
if ( ! fgets_slash ( NULL , line , sizeof ( line ) , f ) )
2003-08-27 05:25:01 +04:00
continue ;
2007-11-20 02:15:09 +03:00
1998-08-30 19:58:17 +04:00
ptr = line ;
2007-12-08 04:32:32 +03:00
frame = talloc_stackframe ( ) ;
if ( ! next_token_talloc ( frame , & ptr , & server , NULL ) | |
! next_token_talloc ( frame , & ptr , & type_str , NULL ) | |
! next_token_talloc ( frame , & ptr , & comment , NULL ) ) {
TALLOC_FREE ( frame ) ;
1998-08-30 19:58:17 +04:00
continue ;
}
sscanf ( type_str , " %X " , & type ) ;
complete_one ( s , server , type , comment ) ;
count + + ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
1998-08-30 19:58:17 +04:00
}
2016-11-26 11:50:33 +03:00
fclose ( f ) ;
1998-08-30 19:58:17 +04:00
unlink ( s - > fname ) ;
DEBUG ( 2 , ( " sync with %s(%s) for workgroup %s completed (%d records) \n " ,
s - > server , inet_ntoa ( s - > ip ) , s - > workgroup , count ) ) ;
}
/**********************************************************************
2003-08-27 05:25:01 +04:00
Check for completion of any of the child processes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-30 19:58:17 +04:00
void sync_check_completion ( void )
{
struct sync_record * s , * next ;
for ( s = syncs ; s ; s = next ) {
next = s - > next ;
2005-09-30 21:13:37 +04:00
if ( ! process_exists_by_pid ( s - > pid ) ) {
1998-08-30 19:58:17 +04:00
/* it has completed - grab the info */
complete_sync ( s ) ;
DLIST_REMOVE ( syncs , s ) ;
2007-11-20 02:15:09 +03:00
SAFE_FREE ( s - > fname ) ;
2001-09-17 08:35:51 +04:00
SAFE_FREE ( s ) ;
1998-08-30 19:58:17 +04:00
}
}
}