diff options
-rw-r--r-- | source4/nbt_server/winsdb.c | 70 | ||||
-rw-r--r-- | source4/nbt_server/winsdb.h | 6 | ||||
-rw-r--r-- | source4/nbt_server/winsserver.c | 2 | ||||
-rw-r--r-- | source4/nbt_server/winswack.c | 10 |
4 files changed, 84 insertions, 4 deletions
diff --git a/source4/nbt_server/winsdb.c b/source4/nbt_server/winsdb.c index 4eff12901f..66e84c668b 100644 --- a/source4/nbt_server/winsdb.c +++ b/source4/nbt_server/winsdb.c @@ -28,6 +28,62 @@ #include "system/time.h" /* + save the min/max version IDs for the database +*/ +static BOOL winsdb_save_version(struct wins_server *winssrv) +{ + int i, ret = 0; + struct ldb_context *ldb = winssrv->wins_db->ldb; + struct ldb_message *msg = ldb_msg_new(winssrv); + if (msg == NULL) goto failed; + + msg->dn = talloc_strdup(msg, "CN=VERSION"); + if (msg->dn == NULL) goto failed; + + ret |= ldb_msg_add_fmt(ldb, msg, "minVersion", "%llu", winssrv->min_version); + ret |= ldb_msg_add_fmt(ldb, msg, "maxVersion", "%llu", winssrv->max_version); + if (ret != 0) goto failed; + + for (i=0;i<msg->num_elements;i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + ret = ldb_modify(ldb, msg); + if (ret != 0) ret = ldb_add(ldb, msg); + if (ret != 0) goto failed; + + talloc_free(msg); + return True; + +failed: + talloc_free(msg); + return False; +} + +/* + allocate a new version id for a record +*/ +static uint64_t winsdb_allocate_version(struct wins_server *winssrv) +{ + winssrv->max_version++; + if (!winsdb_save_version(winssrv)) { + return 0; + } + return winssrv->max_version; +} + +/* + allocate a new version id for a record +*/ +static void winsdb_remove_version(struct wins_server *winssrv, uint64_t version) +{ + if (version == winssrv->min_version) { + winssrv->min_version++; + winsdb_save_version(winssrv); + } +} + +/* load a WINS entry from the database */ struct winsdb_record *winsdb_load(struct wins_server *winssrv, @@ -60,6 +116,7 @@ struct winsdb_record *winsdb_load(struct wins_server *winssrv, rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0); rec->expire_time = ldap_string_to_time(ldb_msg_find_string(res[0], "expires", NULL)); rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL); + rec->version = ldb_msg_find_uint64(res[0], "version", 0); talloc_steal(rec, rec->registered_by); el = ldb_msg_find_element(res[0], "address"); @@ -109,6 +166,7 @@ static struct ldb_message *winsdb_message(struct wins_server *winssrv, ret |= ldb_msg_add_string(ldb, msg, "registeredBy", rec->registered_by); ret |= ldb_msg_add_string(ldb, msg, "expires", ldap_timestring(msg, rec->expire_time)); + ret |= ldb_msg_add_fmt(ldb, msg, "version", "%llu", rec->version); for (i=0;rec->addresses[i];i++) { ret |= ldb_msg_add_string(ldb, msg, "address", rec->addresses[i]); } @@ -130,6 +188,9 @@ uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec) TALLOC_CTX *tmp_ctx = talloc_new(winssrv); int ret; + rec->version = winsdb_allocate_version(winssrv); + if (rec->version == 0) goto failed; + msg = winsdb_message(winssrv, rec, tmp_ctx); if (msg == NULL) goto failed; ret = ldb_add(ldb, msg); @@ -155,6 +216,9 @@ uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec) int ret; int i; + rec->version = winsdb_allocate_version(winssrv); + if (rec->version == 0) goto failed; + msg = winsdb_message(winssrv, rec, tmp_ctx); if (msg == NULL) goto failed; @@ -177,14 +241,16 @@ failed: /* delete a WINS record from the database */ -uint8_t winsdb_delete(struct wins_server *winssrv, struct nbt_name *name) +uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec) { struct ldb_context *ldb = winssrv->wins_db->ldb; TALLOC_CTX *tmp_ctx = talloc_new(winssrv); int ret; const char *dn; - dn = talloc_asprintf(tmp_ctx, "NAME=%s", nbt_name_string(tmp_ctx, name)); + winsdb_remove_version(winssrv, rec->version); + + dn = talloc_asprintf(tmp_ctx, "NAME=%s", nbt_name_string(tmp_ctx, rec->name)); if (dn == NULL) goto failed; ret = ldb_delete(ldb, dn); diff --git a/source4/nbt_server/winsdb.h b/source4/nbt_server/winsdb.h index 0774757ef9..6d395461c6 100644 --- a/source4/nbt_server/winsdb.h +++ b/source4/nbt_server/winsdb.h @@ -35,6 +35,7 @@ struct winsdb_record { time_t expire_time; const char *registered_by; const char **addresses; + uint64_t version; }; struct wins_server { @@ -43,4 +44,9 @@ struct wins_server { uint32_t min_ttl; uint32_t max_ttl; + + /* these are the minimum and maximum record version IDs in the + database. They are needed for replication */ + uint64_t min_version; + uint64_t max_version; }; diff --git a/source4/nbt_server/winsserver.c b/source4/nbt_server/winsserver.c index c1eed0b1fa..6d8770431e 100644 --- a/source4/nbt_server/winsserver.c +++ b/source4/nbt_server/winsserver.c @@ -123,7 +123,7 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, rcode = wins_register_new(nbtsock, packet, src_address, src_port); goto done; } else if (rec->state != WINS_REC_ACTIVE) { - winsdb_delete(winssrv, rec->name); + winsdb_delete(winssrv, rec); rcode = wins_register_new(nbtsock, packet, src_address, src_port); goto done; } diff --git a/source4/nbt_server/winswack.c b/source4/nbt_server/winswack.c index 190b1cdec7..da8efff8d9 100644 --- a/source4/nbt_server/winswack.c +++ b/source4/nbt_server/winswack.c @@ -57,7 +57,15 @@ static void wins_wack_allow(struct wack_state *state) { uint32_t ttl; time_t now = time(NULL); - struct winsdb_record *rec = state->rec; + struct winsdb_record *rec = state->rec, *rec2; + + rec2 = winsdb_load(state->winssrv, rec->name, state); + if (rec2 == NULL || rec2->version != rec->version) { + DEBUG(1,("WINS: record %s changed during WACK - failing registration\n", + nbt_name_string(state, rec->name))); + wins_wack_deny(state); + return; + } nbtd_name_registration_reply(state->nbtsock, state->request_packet, state->src_address, state->src_port, NBT_RCODE_OK); |