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