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;
}
示例#2
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);
}
示例#3
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);
}
示例#4
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;
}