Beispiel #1
0
/*
  handle incoming browse mailslot requests
*/
void nbtd_mailslot_browse_handler(struct dgram_mailslot_handler *dgmslot, 
				  struct nbt_dgram_packet *packet, 
				  struct socket_address *src)
{
	struct nbt_browse_packet *browse = talloc(dgmslot, struct nbt_browse_packet);
	struct nbt_name *name = &packet->data.msg.dest_name;
	NTSTATUS status;

	if (browse == NULL) {
		status = NT_STATUS_INVALID_PARAMETER;
		goto failed;
	}

	status = dgram_mailslot_browse_parse(dgmslot, browse, packet, browse);
	if (!NT_STATUS_IS_OK(status)) goto failed;

	DEBUG(4,("Browse %s (Op %d) on '%s' '%s' from %s:%d\n", 
		nbt_browse_opcode_string(browse->opcode), browse->opcode,
		nbt_name_string(browse, name), dgmslot->mailslot_name,
		src->addr, src->port));

	if (DEBUGLEVEL >= 10) {
		NDR_PRINT_DEBUG(nbt_browse_packet, browse);
	}

	talloc_free(browse);
	return;

failed:
	DEBUG(2,("nbtd browse handler failed from %s:%d to %s - %s\n",
		 src->addr, src->port, nbt_name_string(browse, name),
		 nt_errstr(status)));
	talloc_free(browse);

}
Beispiel #2
0
/*
  called when a wins name register has completed
*/
static void nbtd_wins_register_handler(struct composite_context *c)
{
	NTSTATUS status;
	struct nbt_name_register_wins io;
	struct nbtd_iface_name *iname = talloc_get_type(c->async.private_data, 
							struct nbtd_iface_name);
	TALLOC_CTX *tmp_ctx = talloc_new(iname);

	status = nbt_name_register_wins_recv(c, tmp_ctx, &io);
	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
		/* none of the WINS servers responded - try again 
		   periodically */
		int wins_retry_time = lp_parm_int(iname->iface->nbtsrv->task->lp_ctx, NULL, "nbtd", "wins_retry", 300);
		event_add_timed(iname->iface->nbtsrv->task->event_ctx, 
				iname,
				timeval_current_ofs(wins_retry_time, 0),
				nbtd_wins_register_retry,
				iname);
		talloc_free(tmp_ctx);
		return;
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1,("Name register failure with WINS for %s - %s\n", 
			 nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status)));
		talloc_free(tmp_ctx);
		return;
	}	

	if (io.out.rcode != 0) {
		DEBUG(1,("WINS server %s rejected name register of %s - %s\n", 
			 io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name), 
			 nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
		iname->nb_flags |= NBT_NM_CONFLICT;
		talloc_free(tmp_ctx);
		return;
	}	

	/* success - start a periodic name refresh */
	iname->nb_flags |= NBT_NM_ACTIVE;
	if (iname->wins_server) {
		/*
		 * talloc_free() would generate a warning,
		 * so steal it into the tmp context
		 */
		talloc_steal(tmp_ctx, iname->wins_server);
	}
	iname->wins_server = talloc_steal(iname, io.out.wins_server);

	iname->registration_time = timeval_current();
	nbtd_wins_start_refresh_timer(iname);

	DEBUG(3,("Registered %s with WINS server %s\n",
		 nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));

	talloc_free(tmp_ctx);
}
Beispiel #3
0
/*
  called when a wins name refresh has completed
*/
static void nbtd_wins_refresh_handler(struct composite_context *c)
{
	NTSTATUS status;
	struct nbt_name_refresh_wins io;
	struct nbtd_iface_name *iname = talloc_get_type(c->async.private_data, 
							struct nbtd_iface_name);
	TALLOC_CTX *tmp_ctx = talloc_new(iname);

	status = nbt_name_refresh_wins_recv(c, tmp_ctx, &io);
	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
		/* our WINS server is dead - start registration over
		   from scratch */
		DEBUG(2,("Failed to refresh %s with WINS server %s\n",
			 nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
		talloc_free(tmp_ctx);
		nbtd_winsclient_register(iname);
		return;
	}

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1,("Name refresh failure with WINS for %s - %s\n", 
			 nbt_name_string(tmp_ctx, &iname->name), nt_errstr(status)));
		talloc_free(tmp_ctx);
		return;
	}

	if (io.out.rcode != 0) {
		DEBUG(1,("WINS server %s rejected name refresh of %s - %s\n", 
			 io.out.wins_server, nbt_name_string(tmp_ctx, &iname->name), 
			 nt_errstr(nbt_rcode_to_ntstatus(io.out.rcode))));
		iname->nb_flags |= NBT_NM_CONFLICT;
		talloc_free(tmp_ctx);
		return;
	}	

	DEBUG(4,("Refreshed name %s with WINS server %s\n",
		 nbt_name_string(tmp_ctx, &iname->name), iname->wins_server));
	/* success - start a periodic name refresh */
	iname->nb_flags |= NBT_NM_ACTIVE;
	if (iname->wins_server) {
		/*
		 * talloc_free() would generate a warning,
		 * so steal it into the tmp context
		 */
		talloc_steal(tmp_ctx, iname->wins_server);
	}
	iname->wins_server = talloc_steal(iname, io.out.wins_server);

	iname->registration_time = timeval_current();
	nbtd_wins_start_refresh_timer(iname);

	talloc_free(tmp_ctx);
}
Beispiel #4
0
/*
  handle incoming netlogon mailslot requests
*/
void nbtd_mailslot_netlogon_handler(struct dgram_mailslot_handler *dgmslot, 
				    struct nbt_dgram_packet *packet, 
				    struct socket_address *src)
{
	NTSTATUS status = NT_STATUS_NO_MEMORY;
	struct nbtd_interface *iface = 
		talloc_get_type(dgmslot->private_data, struct nbtd_interface);
	struct nbt_netlogon_packet *netlogon = 
		talloc(dgmslot, struct nbt_netlogon_packet);
	struct nbtd_iface_name *iname;
	struct nbt_name *name = &packet->data.msg.dest_name;

	if (netlogon == NULL) goto failed;

	/*
	  see if the we are listening on the destination netbios name
	*/
	iname = nbtd_find_iname(iface, name, 0);
	if (iname == NULL) {
		status = NT_STATUS_BAD_NETWORK_NAME;
		goto failed;
	}

	DEBUG(5,("netlogon request to %s from %s:%d\n",
		 nbt_name_string(netlogon, name), src->addr, src->port));
	status = dgram_mailslot_netlogon_parse_request(dgmslot, netlogon, packet, netlogon);
	if (!NT_STATUS_IS_OK(status)) goto failed;

	switch (netlogon->command) {
	case LOGON_PRIMARY_QUERY:
		nbtd_netlogon_getdc(dgmslot, iface, packet, 
				    src, netlogon);
		break;
	case LOGON_SAM_LOGON_REQUEST:
		nbtd_netlogon_samlogon(dgmslot, iface, packet, 
				       src, netlogon);
		break;
	default:
		DEBUG(2,("unknown netlogon op %d from %s:%d\n", 
			 netlogon->command, src->addr, src->port));
		NDR_PRINT_DEBUG(nbt_netlogon_packet, netlogon);
		break;
	}

	talloc_free(netlogon);
	return;

failed:
	DEBUG(2,("nbtd netlogon handler failed from %s:%d to %s - %s\n",
		 src->addr, src->port, nbt_name_string(netlogon, name),
		 nt_errstr(status)));
	talloc_free(netlogon);
}
Beispiel #5
0
/*
  do a sgroup merge
*/
static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock, 
				 struct nbt_name_packet *packet, 
			         struct winsdb_record *rec,
			         const char *address,
			         const struct socket_address *src)
{
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);
	struct wins_server *winssrv = iface->nbtsrv->winssrv;
	uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);

	rec->expire_time   = time(NULL) + ttl;
	rec->registered_by = src->addr;

	rec->addresses     = winsdb_addr_list_add(winssrv->wins_db,
						  rec, rec->addresses,
						  address,
						  winssrv->wins_db->local_owner,
						  rec->expire_time,
						  true);
	if (rec->addresses == NULL) return NBT_RCODE_SVR;

	DEBUG(5,("WINS: sgroup merge of %s at %s\n",
		 nbt_name_string(packet, rec->name), address));
	
	return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
}
Beispiel #6
0
/*
  update the ttl on an existing record
*/
static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, 
			       struct nbt_name_packet *packet, 
			       struct winsdb_record *rec,
			       struct winsdb_addr *winsdb_addr,
			       const struct socket_address *src)
{
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);
	struct wins_server *winssrv = iface->nbtsrv->winssrv;
	uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
	const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
	uint32_t modify_flags = 0;

	rec->expire_time   = time(NULL) + ttl;
	rec->registered_by = src->addr;

	if (winsdb_addr) {
		rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
						      rec, rec->addresses,
						      winsdb_addr->address,
						      winssrv->wins_db->local_owner,
						      rec->expire_time,
						      true);
		if (rec->addresses == NULL) return NBT_RCODE_SVR;
	}

	if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
		modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
	}

	DEBUG(5,("WINS: refreshed registration of %s at %s\n",
		 nbt_name_string(packet, rec->name), address));
	
	return winsdb_modify(winssrv->wins_db, rec, modify_flags);
}
Beispiel #7
0
/*
  answer a node status query
*/
void nbtd_query_status(struct nbt_name_socket *nbtsock, 
		       struct nbt_name_packet *packet, 
		       struct socket_address *src)
{
	struct nbt_name *name;
	struct nbtd_iface_name *iname;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
						       struct nbtd_interface);

	NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
	NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_type == NBT_QTYPE_STATUS);
	NBTD_ASSERT_PACKET(packet, src, packet->questions[0].question_class == NBT_QCLASS_IP);

	/* see if we have the requested name on this interface */
	name = &packet->questions[0].name;

	iname = nbtd_find_iname(iface, name, NBT_NM_ACTIVE);
	if (iname == NULL) {
		DEBUG(7,("Node status query for %s from %s - not found on %s\n",
			 nbt_name_string(packet, name), src->addr, iface->ip_address));
		return;
	}

	nbtd_node_status_reply(nbtsock, packet, src, 
			       &iname->name, iface);
}
Beispiel #8
0
/*
  send a name query reply
*/
void nbtd_name_query_reply(struct nbt_name_socket *nbtsock, 
			   struct nbt_name_packet *request_packet, 
			   struct socket_address *src,
			   struct nbt_name *name, uint32_t ttl,
			   uint16_t nb_flags, const char **addresses)
{
	struct nbt_name_packet *packet;
	size_t num_addresses = str_list_length(addresses);
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
						       struct nbtd_interface);
	struct nbtd_server *nbtsrv = iface->nbtsrv;
	int i;

	if (num_addresses == 0) {
		DEBUG(3,("No addresses in name query reply - failing\n"));
		return;
	}

	packet = talloc_zero(nbtsock, struct nbt_name_packet);
	if (packet == NULL) return;

	packet->name_trn_id = request_packet->name_trn_id;
	packet->ancount = 1;
	packet->operation = 
		NBT_FLAG_REPLY | 
		NBT_OPCODE_QUERY | 
		NBT_FLAG_AUTHORITIVE |
		NBT_FLAG_RECURSION_DESIRED |
		NBT_FLAG_RECURSION_AVAIL;

	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
	if (packet->answers == NULL) goto failed;

	packet->answers[0].name     = *name;
	packet->answers[0].rr_type  = NBT_QTYPE_NETBIOS;
	packet->answers[0].rr_class = NBT_QCLASS_IP;
	packet->answers[0].ttl      = ttl;
	packet->answers[0].rdata.netbios.length = num_addresses*6;
	packet->answers[0].rdata.netbios.addresses = 
		talloc_array(packet->answers, struct nbt_rdata_address, num_addresses);
	if (packet->answers[0].rdata.netbios.addresses == NULL) goto failed;

	for (i=0;i<num_addresses;i++) {
		struct nbt_rdata_address *addr = 
			&packet->answers[0].rdata.netbios.addresses[i];
		addr->nb_flags = nb_flags;
		addr->ipaddr = talloc_strdup(packet->answers, addresses[i]);
		if (addr->ipaddr == NULL) goto failed;
	}

	DEBUG(7,("Sending name query reply for %s at %s to %s:%d\n", 
		 nbt_name_string(packet, name), addresses[0], src->addr, src->port));
	
	nbtsrv->stats.total_sent++;
	nbt_name_reply_send(nbtsock, src, packet);

failed:
	talloc_free(packet);
}
Beispiel #9
0
/*
  deny a registration request
*/
static void wins_wack_deny(struct nbtd_wins_wack_state *s)
{
	nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
				     s->src, NBT_RCODE_ACT);
	DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
		 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
	talloc_free(s);
}
Beispiel #10
0
/*
  register a new name with WINS
*/
static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, 
				 struct nbt_name_packet *packet, 
				 const struct socket_address *src,
				 enum wrepl_name_type type)
{
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);
	struct wins_server *winssrv = iface->nbtsrv->winssrv;
	struct nbt_name *name = &packet->questions[0].name;
	uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
	uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
	const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
	struct winsdb_record rec;
	enum wrepl_name_node node;

#define WREPL_NODE_NBT_FLAGS(nb_flags) \
	((nb_flags & NBT_NM_OWNER_TYPE)>>13)

	node	= WREPL_NODE_NBT_FLAGS(nb_flags);

	rec.name		= name;
	rec.type		= type;
	rec.state		= WREPL_STATE_ACTIVE;
	rec.node		= node;
	rec.is_static		= false;
	rec.expire_time		= time(NULL) + ttl;
	rec.version		= 0; /* will be allocated later */
	rec.wins_owner		= NULL; /* will be set later */
	rec.registered_by	= src->addr;
	rec.addresses		= winsdb_addr_list_make(packet);
	if (rec.addresses == NULL) return NBT_RCODE_SVR;

	rec.addresses     = winsdb_addr_list_add(winssrv->wins_db,
						 &rec, rec.addresses,
						 address,
						 winssrv->wins_db->local_owner,
						 rec.expire_time,
						 true);
	if (rec.addresses == NULL) return NBT_RCODE_SVR;

	DEBUG(4,("WINS: accepted registration of %s with address %s\n",
		 nbt_name_string(packet, name), rec.addresses[0]->address));
	
	return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
}
Beispiel #11
0
/*
  called when a name query to a current owner completes
*/
static void wack_wins_challenge_handler(struct composite_context *c_req)
{
	struct nbtd_wins_wack_state *s = talloc_get_type(c_req->async.private_data,
					 struct nbtd_wins_wack_state);
	bool found;
	uint32_t i;

	s->status = wins_challenge_recv(c_req, s, &s->io);

	/*
	 * if the owner denies it holds the name, then allow
	 * the registration
	 */
	if (!NT_STATUS_IS_OK(s->status)) {
		wins_wack_allow(s);
		return;
	}

	if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
		DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
			 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
		wins_wack_deny(s);
		return;
	}

	/*
	 * if the owner still wants the name and doesn't reply
	 * with the address trying to be registered, then deny
	 * the registration
	 */
	found = false;
	for (i=0; i < s->io.out.num_addresses; i++) {
		if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;

		found = true;
		break;
	}
	if (!found) {
		wins_wack_deny(s);
		return;
	}

	wins_wack_allow(s);
	return;
}
Beispiel #12
0
/*
  send a name registration reply
*/
void nbtd_name_registration_reply(struct nbt_name_socket *nbtsock, 
				  struct nbt_name_packet *request_packet, 
				  struct socket_address *src,
				  uint8_t rcode)
{
	struct nbt_name_packet *packet;
	struct nbt_name *name = &request_packet->questions[0].name;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
						       struct nbtd_interface);
	struct nbtd_server *nbtsrv = iface->nbtsrv;

	packet = talloc_zero(nbtsock, struct nbt_name_packet);
	if (packet == NULL) return;

	packet->name_trn_id = request_packet->name_trn_id;
	packet->ancount = 1;
	packet->operation = 
		NBT_FLAG_REPLY | 
		NBT_OPCODE_REGISTER |
		NBT_FLAG_AUTHORITIVE |
		NBT_FLAG_RECURSION_DESIRED |
		NBT_FLAG_RECURSION_AVAIL |
		rcode;
	
	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
	if (packet->answers == NULL) goto failed;

	packet->answers[0].name     = *name;
	packet->answers[0].rr_type  = NBT_QTYPE_NETBIOS;
	packet->answers[0].rr_class = NBT_QCLASS_IP;
	packet->answers[0].ttl      = request_packet->additional[0].ttl;
	packet->answers[0].rdata    = request_packet->additional[0].rdata;

	DEBUG(7,("Sending %s name registration reply for %s to %s:%d\n", 
		 rcode==0?"positive":"negative",
		 nbt_name_string(packet, name), src->addr, src->port));
	
	nbtsrv->stats.total_sent++;
	nbt_name_reply_send(nbtsock, src, packet);

failed:
	talloc_free(packet);
}
Beispiel #13
0
/*
  send a WACK reply
*/
void nbtd_wack_reply(struct nbt_name_socket *nbtsock, 
		     struct nbt_name_packet *request_packet, 
		     struct socket_address *src,
		     uint32_t ttl)
{
	struct nbt_name_packet *packet;
	struct nbt_name *name = &request_packet->questions[0].name;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
						       struct nbtd_interface);
	struct nbtd_server *nbtsrv = iface->nbtsrv;

	packet = talloc_zero(nbtsock, struct nbt_name_packet);
	if (packet == NULL) return;

	packet->name_trn_id = request_packet->name_trn_id;
	packet->ancount = 1;
	packet->operation = 
		NBT_FLAG_REPLY | 
		NBT_OPCODE_WACK |
		NBT_FLAG_AUTHORITIVE;
	
	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
	if (packet->answers == NULL) goto failed;

	packet->answers[0].name              = *name;
	packet->answers[0].rr_type           = NBT_QTYPE_NETBIOS;
	packet->answers[0].rr_class          = NBT_QCLASS_IP;
	packet->answers[0].ttl               = ttl;
	packet->answers[0].rdata.data.length = 2;
	packet->answers[0].rdata.data.data   = talloc_size(packet, 2);
	if (packet->answers[0].rdata.data.data == NULL) goto failed;
	RSSVAL(packet->answers[0].rdata.data.data, 0, request_packet->operation);

	DEBUG(7,("Sending WACK reply for %s to %s:%d\n", 
		 nbt_name_string(packet, name), src->addr, src->port));
	
	nbtsrv->stats.total_sent++;
	nbt_name_reply_send(nbtsock, src, packet);

failed:
	talloc_free(packet);
}
Beispiel #14
0
/*
  send a negative name query reply
*/
void nbtd_negative_name_query_reply(struct nbt_name_socket *nbtsock, 
				    struct nbt_name_packet *request_packet, 
				    struct socket_address *src)
{
	struct nbt_name_packet *packet;
	struct nbt_name *name = &request_packet->questions[0].name;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
						       struct nbtd_interface);
	struct nbtd_server *nbtsrv = iface->nbtsrv;

	packet = talloc_zero(nbtsock, struct nbt_name_packet);
	if (packet == NULL) return;

	packet->name_trn_id = request_packet->name_trn_id;
	packet->ancount = 1;
	packet->operation = 
		NBT_FLAG_REPLY | 
		NBT_OPCODE_QUERY | 
		NBT_FLAG_AUTHORITIVE |
		NBT_RCODE_NAM;

	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
	if (packet->answers == NULL) goto failed;

	packet->answers[0].name      = *name;
	packet->answers[0].rr_type   = NBT_QTYPE_NULL;
	packet->answers[0].rr_class  = NBT_QCLASS_IP;
	packet->answers[0].ttl       = 0;
	ZERO_STRUCT(packet->answers[0].rdata);

	DEBUG(7,("Sending negative name query reply for %s to %s:%d\n", 
		 nbt_name_string(packet, name), src->addr, src->port));
	
	nbtsrv->stats.total_sent++;
	nbt_name_reply_send(nbtsock, src, packet);

failed:
	talloc_free(packet);
}
Beispiel #15
0
/*
  release a name
*/
static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
				    struct nbt_name_packet *packet, 
				    struct socket_address *src)
{
	NTSTATUS status;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);
	struct wins_server *winssrv = iface->nbtsrv->winssrv;
	struct nbt_name *name = &packet->questions[0].name;
	struct winsdb_record *rec;
	uint32_t modify_flags = 0;
	uint8_t ret;

	if (name->type == NBT_NAME_MASTER) {
		goto done;
	}

	if (name->scope && strlen(name->scope) > 237) {
		goto done;
	}

	status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
	if (!NT_STATUS_IS_OK(status)) {
		goto done;
	}

	if (rec->is_static) {
		if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
			goto done;
		}
		nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
		return;
	}

	if (rec->state != WREPL_STATE_ACTIVE) {
		goto done;
	}

	/* 
	 * TODO: do we need to check if
	 *       src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
	 *       here?
	 */

	/* 
	 * we only allow releases from an owner - other releases are
	 * silently ignored
	 */
	if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
		int i;
		DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
		DEBUGADD(4, ("Registered Addresses: \n"));
		for (i=0; rec->addresses && rec->addresses[i]; i++) {
			DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
		}
		goto done;
	}

	DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));

	switch (rec->type) {
	case WREPL_TYPE_UNIQUE:
		rec->state = WREPL_STATE_RELEASED;
		break;

	case WREPL_TYPE_GROUP:
		rec->state = WREPL_STATE_RELEASED;
		break;

	case WREPL_TYPE_SGROUP:
		winsdb_addr_list_remove(rec->addresses, src->addr);
		/* TODO: do we need to take the ownership here? */
		if (winsdb_addr_list_length(rec->addresses) == 0) {
			rec->state = WREPL_STATE_RELEASED;
		}
		break;

	case WREPL_TYPE_MHOMED:
		winsdb_addr_list_remove(rec->addresses, src->addr);
		/* TODO: do we need to take the ownership here? */
		if (winsdb_addr_list_length(rec->addresses) == 0) {
			rec->state = WREPL_STATE_RELEASED;
		}
		break;
	}

	if (rec->state == WREPL_STATE_ACTIVE) {
		/*
		 * If the record is still active, we need to update the
		 * expire_time.
		 *
		 * if we're not the owner, we need to take the ownership.
		 */
		rec->expire_time= time(NULL) + winssrv->config.max_renew_interval;
		if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) != 0) {
			modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
		}
		if (lpcfg_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
			/*
			 * We have an option to propagate every name release,
			 * this is off by default to match windows servers
			 */
			modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
		}
	} else if (rec->state == WREPL_STATE_RELEASED) {
		/*
		 * if we're not the owner, we need to take the owner ship
		 * and make the record tombstone, but expire after
		 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
		 * like for normal tombstone records.
		 * This is to replicate the record directly to the original owner,
		 * where the record is still active
		 */ 
		if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
			rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
		} else {
			rec->state	= WREPL_STATE_TOMBSTONE;
			rec->expire_time= time(NULL) + 
					  winssrv->config.tombstone_interval +
					  winssrv->config.tombstone_timeout;
			modify_flags	= WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
		}
	}

	ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
	if (ret != NBT_RCODE_OK) {
		DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
			nbt_name_string(rec, rec->name), src->addr, ret));
	}
done:
	/* we match w2k3 by always giving a positive reply to name releases. */
	nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
}
Beispiel #16
0
/*
  allow a registration request
*/
static void wins_wack_allow(struct nbtd_wins_wack_state *s)
{
	NTSTATUS status;
	uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
	struct winsdb_record *rec = s->rec, *rec2;
	uint32_t i,j;

	status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
	if (!NT_STATUS_IS_OK(status) ||
	    rec2->version != rec->version ||
	    strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
		DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
			 nbt_name_string(s, rec->name)));
		wins_wack_deny(s);
		return;
	}

	/*
	 * if the old name owner doesn't hold the name anymore
	 * handle the request as new registration for the new name owner
	 */
	if (!NT_STATUS_IS_OK(s->status)) {
		uint8_t rcode;

		winsdb_delete(s->winssrv->wins_db, rec);
		rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
		if (rcode != NBT_RCODE_OK) {
			DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
				 nbt_name_string(s, rec->name)));
			wins_wack_deny(s);
			return;
		}
		goto done;
	}

	rec->expire_time = time(NULL) + ttl;
	rec->registered_by = s->src->addr;

	/*
	 * now remove all addresses that the client doesn't hold anymore
	 * and update the time stamp and owner for the ones that are still there
	 */
	for (i=0; rec->addresses[i]; i++) {
		bool found = false;
		for (j=0; j < s->io.out.num_addresses; j++) {
			if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;

			found = true;
			break;
		}
		if (found) {
			rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
							      rec, rec->addresses,
							      s->reg_address,
							      s->winssrv->wins_db->local_owner,
							      rec->expire_time,
							      true);
			if (rec->addresses == NULL) goto failed;
			continue;
		}

		winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
	}

	rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
					      rec, rec->addresses,
					      s->reg_address,
					      s->winssrv->wins_db->local_owner,
					      rec->expire_time,
					      true);
	if (rec->addresses == NULL) goto failed;

	/* if we have more than one address, this becomes implicit a MHOMED record */
	if (winsdb_addr_list_length(rec->addresses) > 1) {
		rec->type = WREPL_TYPE_MHOMED;
	}

	winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);

	DEBUG(4,("WINS: accepted registration of %s with address %s\n",
		 nbt_name_string(s, rec->name), s->reg_address));

done:
	nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
				     s->src, NBT_RCODE_OK);
failed:
	talloc_free(s);
}
Beispiel #17
0
/*
  register a name
*/
static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, 
				     struct nbt_name_packet *packet, 
				     struct socket_address *src)
{
	NTSTATUS status;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);
	struct wins_server *winssrv = iface->nbtsrv->winssrv;
	struct nbt_name *name = &packet->questions[0].name;
	struct winsdb_record *rec;
	uint8_t rcode = NBT_RCODE_OK;
	uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
	const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
	bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
	enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
	struct winsdb_addr *winsdb_addr = NULL;
	bool duplicate_packet;

	/*
	 * as a special case, the local master browser name is always accepted
	 * for registration, but never stored, but w2k3 stores it if it's registered
	 * as a group name, (but a query for the 0x1D name still returns not found!)
	 */
	if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
		rcode = NBT_RCODE_OK;
		goto done;
	}

	/* w2k3 refuses 0x1B names with marked as group */
	if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
		rcode = NBT_RCODE_RFS;
		goto done;
	}

	/* w2k3 refuses 0x1C names with out marked as group */
	if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
		rcode = NBT_RCODE_RFS;
		goto done;
	}

	/* w2k3 refuses 0x1E names with out marked as group */
	if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
		rcode = NBT_RCODE_RFS;
		goto done;
	}

	if (name->scope && strlen(name->scope) > 237) {
		rcode = NBT_RCODE_SVR;
		goto done;
	}

	duplicate_packet = wins_check_wack_queue(iface, packet, src);
	if (duplicate_packet) {
		/* just ignore the packet */
		DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
			 src->addr, src->port));
		return;
	}

	status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
	if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
		rcode = wins_register_new(nbtsock, packet, src, new_type);
		goto done;
	} else if (!NT_STATUS_IS_OK(status)) {
		rcode = NBT_RCODE_SVR;
		goto done;
	} else if (rec->is_static) {
		if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
			rcode = NBT_RCODE_OK;
			goto done;
		}
		rcode = NBT_RCODE_ACT;
		goto done;
	}

	if (rec->type == WREPL_TYPE_GROUP) {
		if (new_type != WREPL_TYPE_GROUP) {
			DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
				 " while a normal group is already there\n",
				 nbt_name_string(packet, name), new_type));
			rcode = NBT_RCODE_ACT;
			goto done;
		}

		if (rec->state == WREPL_STATE_ACTIVE) {
			/* TODO: is this correct? */
			rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
			goto done;
		}

		/* TODO: is this correct? */
		winsdb_delete(winssrv->wins_db, rec);
		rcode = wins_register_new(nbtsock, packet, src, new_type);
		goto done;
	}

	if (rec->state != WREPL_STATE_ACTIVE) {
		winsdb_delete(winssrv->wins_db, rec);
		rcode = wins_register_new(nbtsock, packet, src, new_type);
		goto done;
	}

	switch (rec->type) {
	case WREPL_TYPE_UNIQUE:
	case WREPL_TYPE_MHOMED:
		/* 
		 * if its an active unique name, and the registration is for a group, then
		 * see if the unique name owner still wants the name
		 * TODO: is this correct?
		 */
		if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
			wins_register_wack(nbtsock, packet, rec, src, new_type);
			return;
		}

		/* 
		 * if the registration is for an address that is currently active, then 
		 * just update the expiry time of the record and the address
		 */
		winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
		if (winsdb_addr) {
			rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
			goto done;
		}

		/*
		 * we have to do a WACK to see if the current owner is willing
		 * to give up its claim
		 */
		wins_register_wack(nbtsock, packet, rec, src, new_type);
		return;

	case WREPL_TYPE_GROUP:
		/* this should not be reached as normal groups are handled above */
		DEBUG(0,("BUG at %s\n",__location__));
		rcode = NBT_RCODE_ACT;
		goto done;

	case WREPL_TYPE_SGROUP:
		/* if the new record isn't also a special group, refuse the registration */ 
		if (new_type != WREPL_TYPE_SGROUP) {
			DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
				 " while a special group is already there\n",
				 nbt_name_string(packet, name), new_type));
			rcode = NBT_RCODE_ACT;
			goto done;
		}

		/* 
		 * if the registration is for an address that is currently active, then 
		 * just update the expiry time of the record and the address
		 */
		winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
		if (winsdb_addr) {
			rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
			goto done;
		}

		rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
		goto done;
	}

done:
	nbtd_name_registration_reply(nbtsock, packet, src, rcode);
}
Beispiel #18
0
/*
  send a name status reply
*/
static void nbtd_node_status_reply(struct nbt_name_socket *nbtsock, 
				   struct nbt_name_packet *request_packet, 
				   struct socket_address *src,
				   struct nbt_name *name, 
				   struct nbtd_interface *iface)
{
	struct nbt_name_packet *packet;
	uint32_t name_count;
	struct nbtd_iface_name *iname;
	struct nbtd_server *nbtsrv = iface->nbtsrv;
	
	/* work out how many names to send */
	name_count = 0;
	for (iname=iface->names;iname;iname=iname->next) {
		if ((iname->nb_flags & NBT_NM_ACTIVE) && 
		    strcmp(iname->name.name, "*") != 0) {
			name_count++;
		}
	}

	packet = talloc_zero(nbtsock, struct nbt_name_packet);
	if (packet == NULL) return;

	packet->name_trn_id = request_packet->name_trn_id;
	packet->ancount = 1;
	packet->operation = NBT_OPCODE_QUERY | NBT_FLAG_REPLY | NBT_FLAG_AUTHORITIVE;

	packet->answers = talloc_array(packet, struct nbt_res_rec, 1);
	if (packet->answers == NULL) goto failed;

	packet->answers[0].name     = *name;
	packet->answers[0].rr_type  = NBT_QTYPE_STATUS;
	packet->answers[0].rr_class = NBT_QCLASS_IP;
	packet->answers[0].ttl      = 0;
	packet->answers[0].rdata.status.num_names = name_count;
	packet->answers[0].rdata.status.names = talloc_array(packet->answers,
							     struct nbt_status_name, name_count);
	if (packet->answers[0].rdata.status.names == NULL) goto failed;

	name_count = 0;
	for (iname=iface->names;iname;iname=iname->next) {
		if ((iname->nb_flags & NBT_NM_ACTIVE) && 
		    strcmp(iname->name.name, "*") != 0) {
			struct nbt_status_name *n = &packet->answers[0].rdata.status.names[name_count];
			n->name = talloc_asprintf(packet->answers, "%-15s", iname->name.name);
			if (n->name == NULL) goto failed;
			n->type     = iname->name.type;
			n->nb_flags = iname->nb_flags;
			name_count++;
		}
	}
	/* we deliberately don't fill in the statistics structure as
	   it could lead to giving attackers too much information */
	ZERO_STRUCT(packet->answers[0].rdata.status.statistics);

	DEBUG(7,("Sending node status reply for %s to %s:%d\n", 
		 nbt_name_string(packet, name), src->addr, src->port));
	
	nbtsrv->stats.total_sent++;
	nbt_name_reply_send(nbtsock, src, packet);

failed:
	talloc_free(packet);
}
Beispiel #19
0
/*
  test operations against a WINS server
*/
static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
			       struct nbt_name *name, uint16_t nb_flags,
			       bool try_low_port)
{
	struct nbt_name_register_wins io;
	struct nbt_name_register name_register;
	struct nbt_name_query query;
	struct nbt_name_refresh_wins refresh;
	struct nbt_name_release release;
	struct nbt_name_request *req;
	NTSTATUS status;
	struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
	const char *myaddress;
	struct socket_address *socket_address;
	struct interface *ifaces;
	bool low_port = try_low_port;

	load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);

	myaddress = talloc_strdup(tctx, iface_best_ip(ifaces, address));

	socket_address = socket_address_from_strings(tctx, 
						     nbtsock->sock->backend_name,
						     myaddress, lp_nbt_port(tctx->lp_ctx));
	torture_assert(tctx, socket_address != NULL, 
				   "Error getting address");

	/* we do the listen here to ensure the WINS server receives the packets from
	   the right IP */
	status = socket_listen(nbtsock->sock, socket_address, 0, 0);
	talloc_free(socket_address);
	if (!NT_STATUS_IS_OK(status)) {
		low_port = false;
		socket_address = socket_address_from_strings(tctx,
							     nbtsock->sock->backend_name,
							     myaddress, 0);
		torture_assert(tctx, socket_address != NULL,
			       "Error getting address");

		status = socket_listen(nbtsock->sock, socket_address, 0, 0);
		talloc_free(socket_address);
		torture_assert_ntstatus_ok(tctx, status,
					   "socket_listen for WINS failed");
	}

	torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n", 
	       nbt_name_string(tctx, name), myaddress, nb_flags);

	torture_comment(tctx, "release the name\n");
	release.in.name = *name;
	release.in.dest_port = lp_nbt_port(tctx->lp_ctx);
	release.in.dest_addr = address;
	release.in.address = myaddress;
	release.in.nb_flags = nb_flags;
	release.in.broadcast = false;
	release.in.timeout = 3;
	release.in.retries = 0;

	status = nbt_name_release(nbtsock, tctx, &release);
	torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
	CHECK_VALUE(tctx, release.out.rcode, 0);

	if (nb_flags & NBT_NM_GROUP) {
		/* ignore this for group names */
	} else if (!low_port) {
		torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
	} else {
		torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
		io.in.name = *name;
		io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
		io.in.wins_servers = str_list_make(tctx, address, NULL);
		io.in.addresses = str_list_make(tctx, "127.64.64.1", NULL);
		io.in.nb_flags = nb_flags;
		io.in.ttl = 300000;

		status = nbt_name_register_wins(nbtsock, tctx, &io);
		if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
			torture_assert_ntstatus_ok(tctx, status,
				talloc_asprintf(tctx, "No response from %s for name register\n",
						address));
		}
		torture_assert_ntstatus_ok(tctx, status,
			talloc_asprintf(tctx, "Bad response from %s for name register\n",
					address));

		CHECK_STRING(tctx, io.out.wins_server, address);
		CHECK_VALUE(tctx, io.out.rcode, 0);

		torture_comment(tctx, "register the name correct address\n");
		name_register.in.name		= *name;
		name_register.in.dest_port	= lp_nbt_port(tctx->lp_ctx);
		name_register.in.dest_addr	= address;
		name_register.in.address	= myaddress;
		name_register.in.nb_flags	= nb_flags;
		name_register.in.register_demand= false;
		name_register.in.broadcast	= false;
		name_register.in.multi_homed	= true;
		name_register.in.ttl		= 300000;
		name_register.in.timeout	= 3;
		name_register.in.retries	= 2;

		/*
		 * test if the server ignores resent requests
		 */
		req = nbt_name_register_send(nbtsock, &name_register);
		while (true) {
			event_loop_once(nbtsock->event_ctx);
			if (req->state != NBT_REQUEST_WAIT) {
				break;
			}
			if (req->received_wack) {
				/*
				 * if we received the wack response
				 * we resend the request and the
				 * server should ignore that
				 * and not handle it as new request
				 */
				req->state = NBT_REQUEST_SEND;
				DLIST_ADD_END(nbtsock->send_queue, req,
					      struct nbt_name_request *);
				EVENT_FD_WRITEABLE(nbtsock->fde);
				break;
			}
		}

		status = nbt_name_register_recv(req, tctx, &name_register);
		if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
			torture_assert_ntstatus_ok(tctx, status,
				talloc_asprintf(tctx, "No response from %s for name register\n",
						address));
		}
		torture_assert_ntstatus_ok(tctx, status,
			talloc_asprintf(tctx, "Bad response from %s for name register\n",
					address));

		CHECK_VALUE(tctx, name_register.out.rcode, 0);
		CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
	}
static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
{
	NTSTATUS status;
	struct winsdb_record *rec = NULL;
	struct ldb_result *res = NULL;
	const char *owner_filter;
	const char *filter;
	uint32_t i;
	int ret;
	time_t now = time(NULL);
	const char *now_timestr;
	const char *action;
	const char *old_state=NULL;
	const char *new_state=NULL;
	uint32_t modify_flags;
	BOOL modify_record;
	BOOL delete_record;
	BOOL delete_tombstones;
	struct timeval tombstone_extra_time;

	now_timestr = ldb_timestring(tmp_mem, now);
	NT_STATUS_HAVE_NO_MEMORY(now_timestr);
	owner_filter = wreplsrv_owner_filter(service, tmp_mem,
					     service->wins_db->local_owner);
	NT_STATUS_HAVE_NO_MEMORY(owner_filter);
	filter = talloc_asprintf(tmp_mem,
				 "(&%s(objectClass=winsRecord)"
				 "(expireTime<=%s))",
				 owner_filter, now_timestr);
	NT_STATUS_HAVE_NO_MEMORY(filter);
	ret = ldb_search(service->wins_db->ldb, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res);
	if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
	talloc_steal(tmp_mem, res);
	DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count));

	tombstone_extra_time = timeval_add(&service->startup_time,
					   service->config.tombstone_extra_timeout,
					   0);
	delete_tombstones = timeval_expired(&tombstone_extra_time);

	for (i=0; i < res->count; i++) {
		/*
		 * we pass '0' as 'now' here,
		 * because we want to get the raw timestamps which are in the DB
		 */
		status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec);
		NT_STATUS_NOT_OK_RETURN(status);
		talloc_free(res->msgs[i]);

		modify_flags	= 0;
		modify_record	= False;
		delete_record	= False;

		switch (rec->state) {
		case WREPL_STATE_ACTIVE:
			old_state	= "active";
			new_state	= "active";
			if (!rec->is_static) {
				new_state	= "released";
				rec->state	= WREPL_STATE_RELEASED;
				rec->expire_time= service->config.tombstone_interval + now;
			}
			modify_flags	= 0;
			modify_record	= True;
			break;

		case WREPL_STATE_RELEASED:
			old_state	= "released";
			new_state	= "tombstone";
			rec->state	= WREPL_STATE_TOMBSTONE;
			rec->expire_time= service->config.tombstone_timeout + now;
			modify_flags	= WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
			modify_record	= True;
			break;

		case WREPL_STATE_TOMBSTONE:
			old_state	= "tombstone";
			new_state	= "tombstone";
			if (!delete_tombstones) break;
			new_state	= "deleted";
			delete_record = True;
			break;

		case WREPL_STATE_RESERVED:
			DEBUG(0,("%s: corrupted record: %s\n",
				__location__, nbt_name_string(rec, rec->name)));
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		if (modify_record) {
			action = "modify";
			ret = winsdb_modify(service->wins_db, rec, modify_flags);
		} else if (delete_record) {
			action = "delete";
			ret = winsdb_delete(service->wins_db, rec);
		} else {
			action = "skip";
			ret = NBT_RCODE_OK;
		}

		if (ret != NBT_RCODE_OK) {
			DEBUG(1,("WINS scavenging: failed to %s name %s (owned:%s -> owned:%s): error:%u\n",
				action, nbt_name_string(rec, rec->name), old_state, new_state, ret));
		} else {
			DEBUG(4,("WINS scavenging: %s name: %s (owned:%s -> owned:%s)\n",
				action, nbt_name_string(rec, rec->name), old_state, new_state));
		}

		talloc_free(rec);
	}

	return NT_STATUS_OK;
}
Beispiel #21
0
/*
  answer a name query
*/
void nbtd_request_query(struct nbt_name_socket *nbtsock, 
			struct nbt_name_packet *packet, 
			struct socket_address *src)
{
	struct nbtd_iface_name *iname;
	struct nbt_name *name;
	struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
						       struct nbtd_interface);

	/* see if its a node status query */
	if (packet->qdcount == 1 &&
	    packet->questions[0].question_type == NBT_QTYPE_STATUS) {
		nbtd_query_status(nbtsock, packet, src);
		return;
	}

	NBTD_ASSERT_PACKET(packet, src, packet->qdcount == 1);
	NBTD_ASSERT_PACKET(packet, src, 
			   packet->questions[0].question_type == NBT_QTYPE_NETBIOS);
	NBTD_ASSERT_PACKET(packet, src, 
			   packet->questions[0].question_class == NBT_QCLASS_IP);

	/* see if we have the requested name on this interface */
	name = &packet->questions[0].name;

	iname = nbtd_find_iname(iface, name, 0);
	if (iname == NULL) {
		/* don't send negative replies to broadcast queries */
		if (packet->operation & NBT_FLAG_BROADCAST) {
			return;
		}

		if (packet->operation & NBT_FLAG_RECURSION_DESIRED) {
			nbtd_winsserver_request(nbtsock, packet, src);
			return;
		}

		/* otherwise send a negative reply */
		nbtd_negative_name_query_reply(nbtsock, packet, src);
		return;
	}

	/*
	 * normally we should forward all queries with the
	 * recursion desired flag to the wins server, but this
	 * breaks are winsclient code, when doing mhomed registrations
	 */
	if (!(packet->operation & NBT_FLAG_BROADCAST) &&
	   (packet->operation & NBT_FLAG_RECURSION_DESIRED) &&
	   (iname->nb_flags & NBT_NM_GROUP) &&
	   lpcfg_wins_support(iface->nbtsrv->task->lp_ctx)) {
		nbtd_winsserver_request(nbtsock, packet, src);
		return;
	}

	/* if the name is not yet active and its a broadcast query then
	   ignore it for now */
	if (!(iname->nb_flags & NBT_NM_ACTIVE) && 
	    (packet->operation & NBT_FLAG_BROADCAST)) {
		DEBUG(7,("Query for %s from %s - name not active yet on %s\n",
			 nbt_name_string(packet, name), src->addr, iface->ip_address));
		return;
	}

	nbtd_name_query_reply(nbtsock, packet, src,
			      &iname->name, iname->ttl, iname->nb_flags, 
			      nbtd_address_list(iface, packet));
}
Beispiel #22
0
static NTSTATUS wreplsrv_scavenging_owned_records(struct wreplsrv_service *service, TALLOC_CTX *tmp_mem)
{
	NTSTATUS status;
	struct winsdb_record *rec = NULL;
	struct ldb_result *res = NULL;
	const char *owner_filter;
	const char *filter;
	unsigned int i;
	int ret;
	time_t now = time(NULL);
	const char *now_timestr;
	const char *action;
	const char *old_state=NULL;
	const char *new_state=NULL;
	uint32_t modify_flags;
	bool modify_record;
	bool delete_record;
	bool delete_tombstones;
	struct timeval tombstone_extra_time;
	const char *local_owner = service->wins_db->local_owner;
	bool propagate = lpcfg_parm_bool(service->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false);

	now_timestr = ldb_timestring(tmp_mem, now);
	NT_STATUS_HAVE_NO_MEMORY(now_timestr);
	owner_filter = wreplsrv_owner_filter(service, tmp_mem, local_owner);
	NT_STATUS_HAVE_NO_MEMORY(owner_filter);
	filter = talloc_asprintf(tmp_mem,
				 "(&%s(objectClass=winsRecord)"
				 "(expireTime<=%s))",
				 owner_filter, now_timestr);
	NT_STATUS_HAVE_NO_MEMORY(filter);
	ret = ldb_search(service->wins_db->ldb, tmp_mem, &res, NULL, LDB_SCOPE_SUBTREE, NULL, "%s", filter);
	if (ret != LDB_SUCCESS) return NT_STATUS_INTERNAL_DB_CORRUPTION;
	DEBUG(10,("WINS scavenging: filter '%s' count %d\n", filter, res->count));

	tombstone_extra_time = timeval_add(&service->startup_time,
					   service->config.tombstone_extra_timeout,
					   0);
	delete_tombstones = timeval_expired(&tombstone_extra_time);

	for (i=0; i < res->count; i++) {
		bool has_replicas = false;

		/*
		 * we pass '0' as 'now' here,
		 * because we want to get the raw timestamps which are in the DB
		 */
		status = winsdb_record(service->wins_db, res->msgs[i], tmp_mem, 0, &rec);
		NT_STATUS_NOT_OK_RETURN(status);
		talloc_free(res->msgs[i]);

		modify_flags	= 0;
		modify_record	= false;
		delete_record	= false;

		switch (rec->state) {
		case WREPL_STATE_ACTIVE:
			old_state	= "active";
			if (rec->is_static) {
				/*
				 *we store it again, so that it won't appear
				 * in the scavenging the next time
				 */
				old_state	= "active(static)";
				new_state	= "active(static)";
				modify_flags	= 0;
				modify_record	= true;
				break;
			}
			if (rec->type != WREPL_TYPE_SGROUP || !propagate) {
				new_state	= "released";
				rec->state	= WREPL_STATE_RELEASED;
				rec->expire_time= service->config.tombstone_interval + now;
				modify_flags	= 0;
				modify_record	= true;
				break;
			}
			/* check if there's any replica address */
			for (i=0;rec->addresses[i];i++) {
				if (strcmp(rec->addresses[i]->wins_owner, local_owner) != 0) {
					has_replicas = true;
					rec->addresses[i]->expire_time= service->config.renew_interval + now;
				}
			}
			if (has_replicas) {
				/* if it has replica addresses propagate them */
				new_state	= "active(propagated)";
				rec->state	= WREPL_STATE_ACTIVE;
				rec->expire_time= service->config.renew_interval + now;
				modify_flags	= WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
				modify_record	= true;
				break;
			}
			/*
			 * if it doesn't have replica addresses, make it a tombstone,
			 * so that the released owned addresses are propagated
			 */
			new_state	= "tombstone";
			rec->state	= WREPL_STATE_TOMBSTONE;
			rec->expire_time= time(NULL) +
					  service->config.tombstone_interval +
					  service->config.tombstone_timeout;
			modify_flags	= WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
			modify_record	= true;
			break;

		case WREPL_STATE_RELEASED:
			old_state	= "released";
			new_state	= "tombstone";
			rec->state	= WREPL_STATE_TOMBSTONE;
			rec->expire_time= service->config.tombstone_timeout + now;
			modify_flags	= WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
			modify_record	= true;
			break;

		case WREPL_STATE_TOMBSTONE:
			old_state	= "tombstone";
			new_state	= "tombstone";
			if (!delete_tombstones) break;
			new_state	= "deleted";
			delete_record = true;
			break;

		case WREPL_STATE_RESERVED:
			DEBUG(0,("%s: corrupted record: %s\n",
				__location__, nbt_name_string(rec, rec->name)));
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		if (modify_record) {
			action = "modify";
			ret = winsdb_modify(service->wins_db, rec, modify_flags);
		} else if (delete_record) {
			action = "delete";
			ret = winsdb_delete(service->wins_db, rec);
		} else {
			action = "skip";
			ret = NBT_RCODE_OK;
		}

		if (ret != NBT_RCODE_OK) {
			DEBUG(2,("WINS scavenging: failed to %s name %s (owned:%s -> owned:%s): error:%u\n",
				action, nbt_name_string(rec, rec->name), old_state, new_state, ret));
		} else {
			DEBUG(4,("WINS scavenging: %s name: %s (owned:%s -> owned:%s)\n",
				action, nbt_name_string(rec, rec->name), old_state, new_state));
		}

		talloc_free(rec);
	}

	return NT_STATUS_OK;
}