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);
}
Пример #2
0
void register_my_workgroup_one_subnet(struct subnet_record *subrec)
{
	int i;

	struct work_record *work;

	/* Create the workgroup on the subnet. */
	if((work = create_workgroup_on_subnet(subrec, lp_workgroup(), 
					      PERMANENT_TTL)) == NULL) {
		DEBUG(0,("register_my_workgroup_and_names: Failed to create my workgroup %s on subnet %s. \
Exiting.\n", lp_workgroup(), subrec->subnet_name));
		return;
	}
Пример #3
0
static void complete_one(struct sync_record *s,
			 char *sname, uint32 stype, char *comment)
{
	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 */
				unstrcpy(work->local_master_browser_name, comment);
			}
		}
		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);
}
Пример #4
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;
  fstring 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--)
    {
      char qname[17];
      uint16 nb_flags;
      int name_type;

      StrnCpy(qname,p,15);
      name_type = CVAL(p,15);
      nb_flags = get_nb_flags(&p[16]);
      trim_string(qname,NULL," ");

      p += 18;

      if(!(nb_flags & NB_GROUP) && (name_type == 0x00) && 
	 server_name[0] == 0) {
	      /* this is almost certainly the server netbios name */
	      fstrcpy(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 */
		fstrcpy(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);
}
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);
}