Beispiel #1
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 #2
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);
}
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 #4
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 #5
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 #6
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;
}