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; }
/* 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); }
/* 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); }
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; }