nmbd_browsesync.c

来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 680 行 · 第 1/2 页

C
680
字号
/*    Unix SMB/CIFS implementation.   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-2003      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 2 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, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */#include "includes.h"/* This is our local master browser list database. */extern ubi_dlList lmb_browserlist[];/****************************************************************************As a domain master browser, do a sync with a local master browser.**************************************************************************/static void sync_with_lmb(struct browse_cache_record *browc){                     	struct work_record *work;	if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {		if( DEBUGLVL( 0 ) ) {			dbgtext( "sync_with_lmb:\n" );			dbgtext( "Failed to get a workgroup for a local master browser " );			dbgtext( "cache entry workgroup " );			dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );		}		return;	}	/* We should only be doing this if we are a domain master browser for		the given workgroup. Ensure this is so. */	if(!AM_DOMAIN_MASTER_BROWSER(work)) {		if( DEBUGLVL( 0 ) ) {			dbgtext( "sync_with_lmb:\n" );			dbgtext( "We are trying to sync with a local master browser " );			dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );			dbgtext( "and we are not a domain master browser on this workgroup.\n" );			dbgtext( "Error!\n" );		}		return;	}	if( DEBUGLVL( 2 ) ) {		dbgtext( "sync_with_lmb:\n" );		dbgtext( "Initiating sync with local master browser " );		dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );		dbgtext( "for workgroup %s\n", browc->work_group );	}	sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);	browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);}/****************************************************************************Sync or expire any local master browsers.**************************************************************************/void dmb_expire_and_sync_browser_lists(time_t t){	static time_t last_run = 0;	struct browse_cache_record *browc;	/* Only do this every 20 seconds. */  	if (t - last_run < 20) 		return;	last_run = t;	expire_lmb_browsers(t);	for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );			browc;			browc = (struct browse_cache_record *)ubi_dlNext( browc ) ) {		if (browc->sync_time < t)			sync_with_lmb(browc);	}}/****************************************************************************As a local master browser, send an announce packet to the domain master browser.**************************************************************************/static void announce_local_master_browser_to_domain_master_browser( struct work_record *work){	pstring outbuf;	unstring myname;	unstring dmb_name;	char *p;	if(ismyip(work->dmb_addr)) {		if( DEBUGLVL( 2 ) ) {			dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );			dbgtext( "We are both a domain and a local master browser for " );			dbgtext( "workgroup %s.  ", work->work_group );			dbgtext( "Do not announce to ourselves.\n" );		}		return;	}	memset(outbuf,'\0',sizeof(outbuf));	p = outbuf;	SCVAL(p,0,ANN_MasterAnnouncement);	p++;	unstrcpy(myname, global_myname());	strupper_m(myname);	myname[15]='\0';	/* The call below does CH_UNIX -> CH_DOS conversion. JRA */	push_pstring_base(p, myname, outbuf);	p = skip_string(p,1);	if( DEBUGLVL( 4 ) ) {		dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );		dbgtext( "Sending local master announce to " );		dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),					work->work_group );	}	/* Target name for send_mailslot must be in UNIX charset. */	pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);	send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),		global_myname(), 0x0, dmb_name, 0x0, 		work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);}/****************************************************************************As a local master browser, do a sync with a domain master browser.**************************************************************************/static void sync_with_dmb(struct work_record *work){	unstring dmb_name;	if( DEBUGLVL( 2 ) ) {		dbgtext( "sync_with_dmb:\n" );		dbgtext( "Initiating sync with domain master browser " );		dbgtext( "%s ", nmb_namestr(&work->dmb_name) );		dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );		dbgtext( "for workgroup %s\n", work->work_group );	}	pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);	sync_browse_lists(work, dmb_name, work->dmb_name.name_type, 		work->dmb_addr, False, True);}/****************************************************************************  Function called when a node status query to a domain master browser IP succeeds.****************************************************************************/static void domain_master_node_status_success(struct subnet_record *subrec,                                              struct userdata_struct *userdata,                                              struct res_rec *answers,                                              struct in_addr from_ip){	struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);	if( work == NULL ) {		if( DEBUGLVL( 0 ) ) {			dbgtext( "domain_master_node_status_success:\n" );			dbgtext( "Unable to find workgroup " );			dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );		}		return;	}	if( DEBUGLVL( 3 ) ) {		dbgtext( "domain_master_node_status_success:\n" );		dbgtext( "Success in node status for workgroup " );		dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );	}  /* Go through the list of names found at answers->rdata and look for     the first SERVER<0x20> name. */	if(answers->rdata != NULL) {		char *p = answers->rdata;		int numnames = CVAL(p, 0);		p += 1;		while (numnames--) {			unstring qname;			uint16 nb_flags;			int name_type;			pull_ascii_nstring(qname, sizeof(qname), p);			name_type = CVAL(p,15);			nb_flags = get_nb_flags(&p[16]);			trim_char(qname,'\0',' ');			p += 18;			if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {				struct nmb_name nmbname;				make_nmb_name(&nmbname, qname, name_type);				/* Copy the dmb name and IP address					into the workgroup struct. */				work->dmb_name = nmbname;				putip((char *)&work->dmb_addr, &from_ip);				/* Do the local master browser announcement to the domain					master browser name and IP. */				announce_local_master_browser_to_domain_master_browser( work );				/* Now synchronise lists with the domain master browser. */				sync_with_dmb(work);				break;			}		}	} else if( DEBUGLVL( 0 ) ) {		dbgtext( "domain_master_node_status_success:\n" );		dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );		dbgtext( "%s.\n", inet_ntoa(from_ip) );	}}/****************************************************************************  Function called when a node status query to a domain master browser IP fails.****************************************************************************/static void domain_master_node_status_fail(struct subnet_record *subrec,                       struct response_record *rrec){	struct userdata_struct *userdata = rrec->userdata;	if( DEBUGLVL( 0 ) ) {		dbgtext( "domain_master_node_status_fail:\n" );		dbgtext( "Doing a node status request to the domain master browser\n" );		dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );		dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );		dbgtext( "Cannot sync browser lists.\n" );	}}/****************************************************************************  Function called when a query for a WORKGROUP<1b> name succeeds.****************************************************************************/static void find_domain_master_name_query_success(struct subnet_record *subrec,                        struct userdata_struct *userdata_in,                        struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec){	/* 	 * Unfortunately, finding the IP address of the Domain Master Browser,	 * as we have here, is not enough. We need to now do a sync to the	 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will	 * respond to the SMBSERVER name. To get this name from IP	 * address we do a Node status request, and look for the first	 * NAME<0x20> in the response, and take that as the server name.	 * We also keep a cache of the Domain Master Browser name for this	 * workgroup in the Workgroup struct, so that if the same IP addess	 * is returned every time, we don't need to do the node status	 * request.	 */	struct work_record *work;	struct nmb_name nmbname;	struct userdata_struct *userdata;	size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;	unstring qname;	pull_ascii_nstring(qname, sizeof(qname), q_name->name);	if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {		if( DEBUGLVL( 0 ) ) {			dbgtext( "find_domain_master_name_query_success:\n" );			dbgtext( "Failed to find workgroup %s\n", qname);		}	return;  }  /* First check if we already have a dmb for this workgroup. */	if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) {		/* Do the local master browser announcement to the domain			master browser name and IP. */		announce_local_master_browser_to_domain_master_browser( work );		/* Now synchronise lists with the domain master browser. */		sync_with_dmb(work);		return;	} else {		zero_ip(&work->dmb_addr);	}	/* Now initiate the node status request. */	/* We used to use the name "*",0x0 here, but some Windows	 * servers don't answer that name. However we *know* they	 * have the name workgroup#1b (as we just looked it up).	 * So do the node status request on this name instead.	 * Found at LBL labs. JRA.	 */	make_nmb_name(&nmbname,work->work_group,0x1b);	/* Put the workgroup name into the userdata so we know	 what workgroup we're talking to when the reply comes	 back. */	/* Setup the userdata_struct - this is copied so we can use	a stack variable for this. */	if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {		DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));		return;	}	userdata->copy_fn = NULL;	userdata->free_fn = NULL;	userdata->userdata_len = strlen(work->work_group)+1;	overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);	node_status( subrec, &nmbname, answer_ip, 		domain_master_node_status_success,		domain_master_node_status_fail,		userdata);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?