void process_workgroup_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
{
	struct dgram_packet *dgram = &p->packet.dgram;
	int ttl = IVAL(buf,1)/1000;
	unstring workgroup_announce_name;
	unstring master_name;
	uint32 servertype = IVAL(buf,23);
	struct work_record *work;
	unstring source_name;
	unstring dest_name;

	START_PROFILE(workgroup_announce);

	pull_ascii_nstring(workgroup_announce_name,sizeof(workgroup_announce_name),buf+5);
	pull_ascii_nstring(master_name,sizeof(master_name),buf+31);
	pull_ascii_nstring(source_name,sizeof(source_name),dgram->source_name.name);
	pull_ascii_nstring(dest_name,sizeof(dest_name),dgram->dest_name.name);

	DEBUG(3,("process_workgroup_announce: from %s<%02x> IP %s to \
%s for workgroup %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
			nmb_namestr(&dgram->dest_name),workgroup_announce_name));

	DEBUG(5,("process_workgroup_announce: ttl=%d server type=%08x master browser=%s\n",
		ttl, servertype, master_name));

	/* Workgroup announcements must only go to the MSBROWSE name. */
	if (!strequal(dest_name, MSBROWSE) || (dgram->dest_name.name_type != 0x1)) {
		DEBUG(0,("process_workgroup_announce: from IP %s should be to __MSBROWSE__<0x01> not %s\n",
			inet_ntoa(p->ip), nmb_namestr(&dgram->dest_name)));
		goto done;
	}

	if ((work = find_workgroup_on_subnet(subrec, workgroup_announce_name))==NULL) {
		/* We have no record of this workgroup. Add it. */
		if((work = create_workgroup_on_subnet(subrec, workgroup_announce_name, ttl))==NULL)
			goto done;
	} else {
		/* Update the workgroup death_time. */
		update_workgroup_ttl(work, ttl);
	}

	if(*work->local_master_browser_name == '\0') {
		/* Set the master browser name. */
		set_workgroup_local_master_browser_name( work, master_name );
	}

	subrec->work_changed = True;

done:

	END_PROFILE(workgroup_announce);
}
Beispiel #2
0
BOOL queue_dns_query(struct packet_struct *p,struct nmb_name *question)
{
	struct name_record *namerec = NULL;
	struct in_addr dns_ip;
	unstring qname;

	pull_ascii_nstring(qname, sizeof(qname), question->name);

	DEBUG(3,("DNS search for %s - ", nmb_namestr(question)));

        /* Unblock TERM signal so we can be killed in DNS lookup. */
        BlockSignals(False, SIGTERM);

	dns_ip.s_addr = interpret_addr(qname);

        /* Re-block TERM signal. */
        BlockSignals(True, SIGTERM);

	namerec = add_dns_result(question, dns_ip);
	if(namerec == NULL) {
		send_wins_name_query_response(NAM_ERR, p, NULL);
	} else {
		send_wins_name_query_response(0, p, namerec);
	}
	return False;
}
Beispiel #3
0
void sync_all_dmbs(time_t t)
{
	static time_t lastrun = 0;
	struct work_record *work;
	int count=0;

	/* Only do this if we are using a WINS server. */
	if(we_are_a_wins_client() == False)
		return;

	/* Check to see if we are a domain master browser on the
           unicast subnet. */
	work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
	if (!work)
		return;

	if (!AM_DOMAIN_MASTER_BROWSER(work))
		return;

	if ((lastrun != 0) && (t < lastrun + (5 * 60)))
		return;
     
	/* count how many syncs we might need to do */
	for (work=unicast_subnet->workgrouplist; work; work = work->next) {
		if (strcmp(lp_workgroup(), work->work_group)) {
			count++;
		}
	}

	/* sync with a probability of 1/count */
	for (work=unicast_subnet->workgrouplist; work; work = work->next) {
		if (strcmp(lp_workgroup(), work->work_group)) {
			unstring dmb_name;

			if (((unsigned)sys_random()) % count != 0)
				continue;

			lastrun = t;

			if (!work->dmb_name.name[0]) {
				/* we don't know the DMB - assume it is
				   the same as the unicast local master */
				make_nmb_name(&work->dmb_name, 
					      work->local_master_browser_name,
					      0x20);
			}

			pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);

			DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
				 dmb_name, inet_ntoa(work->dmb_addr)));

			sync_browse_lists(work, 
					  dmb_name,
					  work->dmb_name.name_type, 
					  work->dmb_addr, False, False);
		}
	}
}
static void check_for_master_browser_success(struct subnet_record *subrec,
                                 struct userdata_struct *userdata,
                                 struct nmb_name *answer_name,
                                 struct in_addr answer_ip, struct res_rec *rrec)
{
	unstring aname;
	pull_ascii_nstring(aname, sizeof(aname), answer_name->name);
	DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \
IP %s (just checking).\n", aname, inet_ntoa(answer_ip) ));
}
static void become_domain_master_fail(struct subnet_record *subrec,
                                      struct response_record *rrec,
                                      struct nmb_name *fail_name)
{
	unstring failname;
	struct work_record *work;
	struct server_record *servrec;

	pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
	work = find_workgroup_on_subnet(subrec, failname);
	if(!work) {
		DEBUG(0,("become_domain_master_fail: Error - cannot find \
workgroup %s on subnet %s\n", failname, subrec->subnet_name));
		return;
	}
void register_name(struct subnet_record *subrec,
                   const char *name, int type, uint16 nb_flags,
                   register_name_success_function success_fn,
                   register_name_fail_function fail_fn,
                   struct userdata_struct *userdata)
{
	struct nmb_name nmbname;
	nstring nname;

	errno = 0;
	push_ascii_nstring(nname, name);
        if (errno == E2BIG) {
		unstring tname;
		pull_ascii_nstring(tname, sizeof(tname), nname);
		DEBUG(0,("register_name: NetBIOS name %s is too long. Truncating to %s\n",
			name, tname));
		make_nmb_name(&nmbname, tname, type);
	} else {
		make_nmb_name(&nmbname, name, type);
	}

	/* Always set the NB_ACTIVE flag on the name we are
	   registering. Doesn't make sense without it.
	*/
	
	nb_flags |= NB_ACTIVE;
	
	if (subrec == unicast_subnet) {
		/* we now always do multi-homed registration if we are
		   registering to a WINS server. This copes much
		   better with complex WINS setups */
		multihomed_register_name(&nmbname, nb_flags,
					 success_fn, fail_fn);
		return;
	}
	
	if (queue_register_name(subrec,
				register_name_response,
				register_name_timeout_response,
				success_fn,
				fail_fn,
				userdata,
				&nmbname,
				nb_flags) == NULL) {
		DEBUG(0,("register_name: Failed to send packet trying to register name %s\n",
			 nmb_namestr(&nmbname)));
	}
}
Beispiel #7
0
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);
}
static void name_to_unstring(unstring unname, const char *name)
{
        nstring nname;

	errno = 0;
	push_ascii_nstring(nname, name);
	if (errno == E2BIG) {
		unstring tname;
		pull_ascii_nstring(tname, sizeof(tname), nname);
		strlcpy(unname, tname, sizeof(nname));
		DEBUG(0,("name_to_nstring: workgroup name %s is too long. Truncating to %s\n",
			name, tname));
	} else {
		unstrcpy(unname, name);
	}
}
Beispiel #9
0
static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
{
	char outbuf[1024];
	unstring myname;
	unstring dmb_name;
	char *p;

	if(ismyip_v4(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, lp_netbios_name());
	if (!strupper_m(myname)) {
		DEBUG(2,("strupper_m %s failed\n", myname));
		return;
	}
	myname[15]='\0';
	/* The call below does CH_UNIX -> CH_DOS conversion. JRA */
	push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);

	p = skip_string(outbuf,sizeof(outbuf),p);

	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),
		lp_netbios_name(), 0x0, dmb_name, 0x0,
		work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
}
Beispiel #10
0
void insert_permanent_name_into_unicast( struct subnet_record *subrec, 
                                                struct nmb_name *nmbname, uint16 nb_type )
{
	unstring name;
	struct name_record *namerec;

	if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
		pull_ascii_nstring(name, sizeof(name), nmbname->name);
		/* The name needs to be created on the unicast subnet. */
		(void)add_name_to_subnet( unicast_subnet, name,
				nmbname->name_type, nb_type,
				PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
	} else {
		/* The name already exists on the unicast subnet. Add our local
		IP for the given broadcast subnet to the name. */
		add_ip_to_name_record( namerec, subrec->myip);
	}
}
void process_master_browser_announce(struct subnet_record *subrec, 
                                     struct packet_struct *p,char *buf)
{
	unstring local_master_name;
	struct work_record *work;
	struct browse_cache_record *browrec;

	START_PROFILE(master_browser_announce);

	pull_ascii_nstring(local_master_name,sizeof(local_master_name),buf);
  
	DEBUG(3,("process_master_browser_announce: Local master announce from %s IP %s.\n",
		local_master_name, inet_ntoa(p->ip)));
  
	if (!lp_domain_master()) {
		DEBUG(0,("process_master_browser_announce: Not configured as domain \
master - ignoring master announce.\n"));
		goto done;
	}
Beispiel #12
0
/***************************************************************************
  handle DNS queries arriving from the parent
  ****************************************************************************/
static void asyncdns_process(void)
{
	struct query_record r;
	unstring qname;

	DEBUGLEVEL = -1;

	while (1) {
		if (read_data(fd_in, (char *)&r, sizeof(r)) != sizeof(r)) 
			break;

		pull_ascii_nstring( qname, sizeof(qname), r.name.name);
		r.result.s_addr = interpret_addr(qname);

		if (write_data(fd_out, (char *)&r, sizeof(r)) != sizeof(r))
			break;
	}

	_exit(0);
}
static void check_for_master_browser_fail( struct subnet_record *subrec,
                                           struct response_record *rrec,
                                           struct nmb_name *question_name,
                                           int fail_code)
{
	unstring workgroup_name;
	struct work_record *work;

	pull_ascii_nstring(workgroup_name,sizeof(workgroup_name),question_name->name);

	work = find_workgroup_on_subnet(subrec, workgroup_name);
	if(work == NULL) {
		DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n",
			workgroup_name, subrec->subnet_name ));
		return;
	}

	if (strequal(work->work_group, lp_workgroup())) {

		if (lp_local_master()) {
			/* We have discovered that there is no local master
				browser, and we are configured to initiate
				an election that we will participate in.
			*/
			DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n",
				work->work_group, subrec->subnet_name ));

			/* Setting this means we will participate when the
				election is run in run_elections(). */
			work->needelection = True;
		} else {
			/* We need to force an election, because we are configured
				not to become the local master, but we still need one,
				having detected that one doesn't exist.
			*/
			send_election_dgram(subrec, work->work_group, 0, 0, "");
		}
	}
}
Beispiel #14
0
static struct name_record *add_dns_result(struct nmb_name *question, struct in_addr addr)
{
	int name_type = question->name_type;
	unstring qname;

	pull_ascii_nstring(qname, sizeof(qname), question->name);
  
	if (!addr.s_addr) {
		/* add the fail to WINS cache of names. give it 1 hour in the cache */
		DEBUG(3,("add_dns_result: Negative DNS answer for %s\n", qname));
		add_name_to_subnet( wins_server_subnet, qname, name_type,
				NB_ACTIVE, 60*60, DNSFAIL_NAME, 1, &addr );
		return NULL;
	}

	/* add it to our WINS cache of names. give it 2 hours in the cache */
	DEBUG(3,("add_dns_result: DNS gave answer for %s of %s\n", qname, inet_ntoa(addr)));

	add_name_to_subnet( wins_server_subnet, qname, name_type,
                              NB_ACTIVE, 2*60*60, DNS_NAME, 1, &addr);

	return find_name_on_subnet(wins_server_subnet, question, FIND_ANY_NAME);
}
void process_local_master_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
{
	struct dgram_packet *dgram = &p->packet.dgram;
	int ttl = IVAL(buf,1)/1000;
	unstring server_name;
	uint32 servertype = IVAL(buf,23);
	fstring comment;
	unstring work_name;
	struct work_record *work;
	struct server_record *servrec;
	unstring source_name;

	START_PROFILE(local_master_announce);

	pull_ascii_nstring(server_name,sizeof(server_name),buf+5);
	pull_ascii_fstring(comment, buf+31);
	pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);
	pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);

	DEBUG(3,("process_local_master_announce: from %s<%02x> IP %s to \
%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
		nmb_namestr(&dgram->dest_name),server_name));

	DEBUG(5,("process_local_master_announce: ttl=%d server type=%08x comment=%s\n",
		ttl, servertype, comment));

	/* A local master announcement must be sent to the name WORKGROUP<1e>. */
	if(dgram->dest_name.name_type != 0x1e) {
		DEBUG(0,("process_local_master_announce: incorrect name type for destination from IP %s \
(was %02x) should be 0x1e. Ignoring packet.\n",
			inet_ntoa(p->ip), dgram->dest_name.name_type));
		goto done;
	}

	/* Filter servertype to remove impossible bits. */
	servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);

	/* For a local master announce the workgroup name is the destination name. */

	if ((work = find_workgroup_on_subnet(subrec, work_name))==NULL) {
		/* Don't bother adding if it's a local master release announce. */
		if(servertype == 0)
			goto done;

		/* We have no record of this workgroup. Add it. */
		if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
			goto done;
	}

	/* If we think we're the local master browser for this workgroup,
		we should never have got this packet. We don't see our own
		packets.
	*/
	if(AM_LOCAL_MASTER_BROWSER(work)) {
		DEBUG(0,("process_local_master_announce: Server %s at IP %s is announcing itself as \
a local master browser for workgroup %s and we think we are master. Forcing election.\n",
			server_name, inet_ntoa(p->ip), work_name));

		/* Samba nmbd versions 1.9.17 to 1.9.17p4 have a bug in that when
		 they have become a local master browser once, they will never
		 stop sending local master announcements. To fix this we send
		 them a reset browser packet, with level 0x2 on the __SAMBA__
		 name that only they should be listening to. */
   
		send_browser_reset( 0x2, "__SAMBA__" , 0x20, p->ip);

		/* We should demote ourself and force an election. */

		unbecome_local_master_browser( subrec, work, True);

		/* The actual election requests are handled in nmbd_election.c */
		goto done;
	}  

	/* Find the server record on this workgroup. If it doesn't exist, add it. */

	if(servertype != 0) {
		if((servrec = find_server_in_workgroup( work, server_name))==NULL) {
			/* If this server is not already in the workgroup, add it. */
			create_server_on_workgroup(work, server_name, 
				servertype|SV_TYPE_LOCAL_LIST_ONLY, 
				ttl, comment);
		} else {
			/* Update the record. */
			servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
			update_server_ttl(servrec, ttl);
			fstrcpy(servrec->serv.comment,comment);
		}
	
		set_workgroup_local_master_browser_name( work, server_name );
	} else {
		/*
		 * This server is announcing it is going down. Remove it from the
		 * workgroup.
		 */
		if(!is_myname(server_name) && (work != NULL) &&
				((servrec = find_server_in_workgroup( work, server_name))!=NULL)) {
			remove_server_from_workgroup( work, servrec);
		}
	}

	subrec->work_changed = True;
done:

	END_PROFILE(local_master_announce);
}
Beispiel #16
0
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) );
	}
}
Beispiel #17
0
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);

	zero_free(userdata, size);
}
static void multihomed_register_name(struct nmb_name *nmbname, uint16 nb_flags,
				     register_name_success_function success_fn,
				     register_name_fail_function fail_fn)
{
	/*
	  If we are adding a group name, we just send multiple
	  register name packets to the WINS server (this is an
	  internet group name.

	  If we are adding a unique name, We need first to add 
	  our names to the unicast subnet namelist. This is 
	  because when a WINS server receives a multihomed 
	  registration request, the first thing it does is to 
	  send a name query to the registering machine, to see 
	  if it has put the name in it's local namelist.
	  We need the name there so the query response code in
	  nmbd_incomingrequests.c will find it.

	  We are adding this name prematurely (we don't really
	  have it yet), but as this is on the unicast subnet
	  only we will get away with this (only the WINS server
	  will ever query names from us on this subnet).
	*/
	int num_ips=0;
	int i, t;
	struct subnet_record *subrec;
	char **wins_tags;
	struct in_addr *ip_list;
	unstring name;

	for(subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec) )
		num_ips++;
	
	if((ip_list = SMB_MALLOC_ARRAY(struct in_addr, num_ips))==NULL) {
		DEBUG(0,("multihomed_register_name: malloc fail !\n"));
		return;
	}

	for (subrec = FIRST_SUBNET, i = 0; 
	     subrec;
	     subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec), i++ ) {
		ip_list[i] = subrec->myip;
	}

	pull_ascii_nstring(name, sizeof(name), nmbname->name);
	add_name_to_subnet(unicast_subnet, name, nmbname->name_type,
			   nb_flags, lp_max_ttl(), SELF_NAME,
			   num_ips, ip_list);

	/* get the list of wins tags - we try to register for each of them */
	wins_tags = wins_srv_tags();

	/* Now try and register the name for each wins tag.  Note that
	   at this point we only register our first IP with each wins
	   group. We will register the rest from
	   wins_next_registration() when we get the reply for this
	   one. That follows the way W2K does things (tridge)
	*/
	for (t=0; wins_tags && wins_tags[t]; t++) {
		multihomed_register_one(nmbname, nb_flags,
					success_fn, fail_fn,
					ip_list[0],
					wins_tags[t]);
	}

	wins_srv_tags_free(wins_tags);
	
	SAFE_FREE(ip_list);
}
static void register_name_response(struct subnet_record *subrec,
                       struct response_record *rrec, struct packet_struct *p)
{
	/* 
	 * If we are registering broadcast, then getting a response is an
	 * error - we do not have the name. If we are registering unicast,
	 * then we expect to get a response.
	 */

	struct nmb_packet *nmb = &p->packet.nmb;
	BOOL bcast = nmb->header.nm_flags.bcast;
	BOOL success = True;
	struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
	struct nmb_name *answer_name = &nmb->answers->rr_name;
	struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
	int ttl = 0;
	uint16 nb_flags = 0;
	struct in_addr register_ip;
	fstring reg_name;
	
	putip(&register_ip,&sent_nmb->additional->rdata[2]);
	fstrcpy(reg_name, inet_ntoa(register_ip));
	
	if (subrec == unicast_subnet) {
		/* we know that this wins server is definately alive - for the moment! */
		wins_srv_alive(rrec->packet->ip, register_ip);
	}

	/* Sanity check. Ensure that the answer name in the incoming packet is the
	   same as the requested name in the outgoing packet. */

	if(!question_name || !answer_name) {
		DEBUG(0,("register_name_response: malformed response (%s is NULL).\n",
			 question_name ? "question_name" : "answer_name" ));
		return;
	}

	if(!nmb_name_equal(question_name, answer_name)) {
		DEBUG(0,("register_name_response: Answer name %s differs from question name %s.\n", 
			 nmb_namestr(answer_name), nmb_namestr(question_name)));
		return;
	}

	if(bcast) {
		/*
		 * Special hack to cope with old Samba nmbd's.
		 * Earlier versions of Samba (up to 1.9.16p11) respond 
		 * to a broadcast name registration of WORKGROUP<1b> when 
		 * they should not. Hence, until these versions are gone, 
		 * we should treat such errors as success for this particular
		 * case only. [email protected].
		 */
		
#if 1 /* OLD_SAMBA_SERVER_HACK */
		unstring ans_name;
		pull_ascii_nstring(ans_name, sizeof(ans_name), answer_name->name);
		if((nmb->header.rcode == ACT_ERR) && strequal(lp_workgroup(), ans_name) &&
		   (answer_name->name_type == 0x1b)) {
			/* Pretend we did not get this. */
			rrec->num_msgs--;

			DEBUG(5,("register_name_response: Ignoring broadcast response to registration of name %s due to old Samba server bug.\n", 
				 nmb_namestr(answer_name)));
			return;
		}
#endif /* OLD_SAMBA_SERVER_HACK */

		/* Someone else has the name. Log the problem. */
		DEBUG(1,("register_name_response: Failed to register name %s IP %s on subnet %s via broadcast. Error code was %d. Reject came from IP %s\n", 
			 nmb_namestr(answer_name), 
			 reg_name,
			 subrec->subnet_name, nmb->header.rcode, inet_ntoa(p->ip)));
		success = False;
	} else {
		/* Unicast - check to see if the response allows us to have the name. */
		if (nmb->header.opcode == NMB_WACK_OPCODE) {
			/* WINS server is telling us to wait. Pretend we didn't get
			   the response but don't send out any more register requests. */

			DEBUG(5,("register_name_response: WACK from WINS server %s in registering name %s IP %s\n", 
				 inet_ntoa(p->ip), nmb_namestr(answer_name), reg_name));

			rrec->repeat_count = 0;
			/* How long we should wait for. */
			rrec->repeat_time = p->timestamp + nmb->answers->ttl;
			rrec->num_msgs--;
			return;
		} else if (nmb->header.rcode != 0) {
			/* Error code - we didn't get the name. */
			success = False;

			DEBUG(0,("register_name_response: %sserver at IP %s rejected our name registration of %s IP %s with error code %d.\n", 
				 subrec==unicast_subnet?"WINS ":"",
				 inet_ntoa(p->ip), 
				 nmb_namestr(answer_name), 
				 reg_name,
				 nmb->header.rcode));
		} else {
			success = True;
			/* Get the data we need to pass to the success function. */
			nb_flags = get_nb_flags(nmb->answers->rdata);
			ttl = nmb->answers->ttl;

			/* send off a registration for the next IP, if any */
			wins_next_registration(rrec);
		}
	} 

	DEBUG(5,("register_name_response: %s in registering %sname %s IP %s with %s.\n",
		 success ? "success" : "failure", 
		 subrec==unicast_subnet?"WINS ":"",
		 nmb_namestr(answer_name), 
		 reg_name,
		 inet_ntoa(rrec->packet->ip)));

	if(success) {
		/* Enter the registered name into the subnet name database before calling
		   the success function. */
		standard_success_register(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
		if( rrec->success_fn)
			(*(register_name_success_function)rrec->success_fn)(subrec, rrec->userdata, answer_name, nb_flags, ttl, register_ip);
	} else {
		if( rrec->fail_fn)
			(*(register_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name);
		/* Remove the name. */
		standard_fail_register( subrec, rrec, question_name);
	}

	/* Ensure we don't retry. */
	remove_response_record(subrec, rrec);
}
Beispiel #20
0
static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
                                              struct userdata_struct *userdata,
                                              struct res_rec *answers,
                                              struct in_addr from_ip)
{
	struct work_record *work;
	unstring server_name;

	server_name[0] = 0;

	if( DEBUGLVL( 3 ) ) {
		dbgtext( "get_domain_master_name_node_status_success:\n" );
		dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
	}

	/* 
	 * Go through the list of names found at answers->rdata and look for
	 * the first WORKGROUP<0x1b> 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 == 0x00) && 
					server_name[0] == 0) {
				/* this is almost certainly the server netbios name */
				unstrcpy(server_name, qname);
				continue;
			}

			if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
				if( DEBUGLVL( 5 ) ) {
					dbgtext( "get_domain_master_name_node_status_success:\n" );
					dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
					dbgtext( "is a domain master browser for workgroup " );
					dbgtext( "%s. Adding this name.\n", qname );
				}

				/* 
				 * If we don't already know about this workgroup, add it
				 * to the workgroup list on the unicast_subnet.
				 */

				if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
					struct nmb_name nmbname;
					/* 
					 * Add it - with an hour in the cache.
					 */
					if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
						return;

					/* remember who the master is */
					unstrcpy(work->local_master_browser_name, server_name);
					make_nmb_name(&nmbname, server_name, 0x20);
					work->dmb_name = nmbname;
					work->dmb_addr = from_ip;
				}
				break;
			}
		}
	} else if( DEBUGLVL( 0 ) ) {
		dbgtext( "get_domain_master_name_node_status_success:\n" );
		dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
		dbgtext( "%s.\n", inet_ntoa(from_ip) );
	}
}
void process_host_announce(struct subnet_record *subrec, struct packet_struct *p, char *buf)
{
	struct dgram_packet *dgram = &p->packet.dgram;
	int ttl = IVAL(buf,1)/1000;
	unstring announce_name;
	uint32 servertype = IVAL(buf,23);
	fstring comment;
	struct work_record *work;
	struct server_record *servrec;
	unstring work_name;
	unstring source_name;

	START_PROFILE(host_announce);

	pull_ascii_fstring(comment, buf+31);
  
	pull_ascii_nstring(announce_name, sizeof(announce_name), buf+5);
	pull_ascii_nstring(source_name, sizeof(source_name), dgram->source_name.name);

	DEBUG(3,("process_host_announce: from %s<%02x> IP %s to \
%s for server %s.\n", source_name, source_name[15], inet_ntoa(p->ip),
			nmb_namestr(&dgram->dest_name),announce_name));

	DEBUG(5,("process_host_announce: ttl=%d server type=%08x comment=%s\n",
		ttl, servertype,comment));

	/* Filter servertype to remove impossible bits. */
	servertype &= ~(SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM);

	/* A host announcement must be sent to the name WORKGROUP<1d>. */
	if(dgram->dest_name.name_type != 0x1d) {
		DEBUG(2,("process_host_announce: incorrect name type for destination from IP %s \
(was %02x) should be 0x1d. Allowing packet anyway.\n",
			inet_ntoa(p->ip), dgram->dest_name.name_type));
		/* Change it so it was. */
		dgram->dest_name.name_type = 0x1d;
	}

	/* For a host announce the workgroup name is the destination name. */
	pull_ascii_nstring(work_name, sizeof(work_name), dgram->dest_name.name);

	/*
	 * Syntax servers version 5.1 send HostAnnounce packets to
	 * *THE WRONG NAME*. They send to LOCAL_MASTER_BROWSER_NAME<00>
	 * instead of WORKGROUP<1d> name. So to fix this we check if
	 * the workgroup name is our own name, and if so change it
	 * to be our primary workgroup name.
	 */

	if(strequal(work_name, global_myname()))
		unstrcpy(work_name,lp_workgroup());

	/*
	 * We are being very agressive here in adding a workgroup
	 * name on the basis of a host announcing itself as being
	 * in that workgroup. Maybe we should wait for the workgroup
	 * announce instead ? JRA.
	 */

	work = find_workgroup_on_subnet(subrec, work_name);

	if(servertype != 0) {
		if (work ==NULL ) {
			/* We have no record of this workgroup. Add it. */
			if((work = create_workgroup_on_subnet(subrec, work_name, ttl))==NULL)
				goto done;
		}
  
		if((servrec = find_server_in_workgroup( work, announce_name))==NULL) {
			/* If this server is not already in the workgroup, add it. */
			create_server_on_workgroup(work, announce_name, 
				servertype|SV_TYPE_LOCAL_LIST_ONLY, 
				ttl, comment);
		} else {
			/* Update the record. */
			servrec->serv.type = servertype|SV_TYPE_LOCAL_LIST_ONLY;
			update_server_ttl( servrec, ttl);
			fstrcpy(servrec->serv.comment,comment);
		}
	} else {
		/*
		 * This server is announcing it is going down. Remove it from the 
		 * workgroup.
		 */
		if(!is_myname(announce_name) && (work != NULL) &&
				((servrec = find_server_in_workgroup( work, announce_name))!=NULL)) {
			remove_server_from_workgroup( work, servrec);
		}
	}

	subrec->work_changed = True;
done:

	END_PROFILE(host_announce);
}