From 676b220f3e8c975824bfdae407e9f7938d79118c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 14 Oct 2005 12:55:59 +0000 Subject: [PATCH] r11040: r10357@SERNOX: metze | 2005-09-20 21:28:11 +0200 - as the old records are broken sinse the last winsdb_dn() changes, (the dn components order was reversed) we can use nicer attribute and objectClass names... - use much more verbose error handling for winsdb_* - print a debug message when we found a corrupted record metze (This used to be commit 82bad3f3efec5b706a65e65054787f1486d7c875) --- source4/nbt_server/wins/winsdb.c | 136 ++++++++++++++++++--------- source4/nbt_server/wins/winsserver.c | 18 ++-- source4/nbt_server/wins/winswack.c | 5 +- source4/wrepl_server/wrepl_in_call.c | 13 +-- source4/wrepl_server/wrepl_server.c | 6 +- 5 files changed, 115 insertions(+), 63 deletions(-) diff --git a/source4/nbt_server/wins/winsdb.c b/source4/nbt_server/wins/winsdb.c index 551bc857275..ff3c787eb03 100644 --- a/source4/nbt_server/wins/winsdb.c +++ b/source4/nbt_server/wins/winsdb.c @@ -83,7 +83,7 @@ static struct ldb_dn *winsdb_dn(TALLOC_CTX *mem_ctx, struct nbt_name *name) { struct ldb_dn *dn; - dn = ldb_dn_string_compose(mem_ctx, NULL, "type=%02x", name->type); + dn = ldb_dn_string_compose(mem_ctx, NULL, "type=0x%02X", name->type); if (dn && name->name && *name->name) { dn = ldb_dn_string_compose(mem_ctx, dn, "name=%s", name->name); } @@ -93,15 +93,20 @@ static struct ldb_dn *winsdb_dn(TALLOC_CTX *mem_ctx, struct nbt_name *name) return dn; } -struct nbt_name *winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn) +static NTSTATUS winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct nbt_name **_name) { + NTSTATUS status; struct nbt_name *name; uint32_t cur = 0; name = talloc(mem_ctx, struct nbt_name); - if (!name) goto failed; + if (!name) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } if (dn->comp_num > 3) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; goto failed; } @@ -117,26 +122,31 @@ struct nbt_name *winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn) cur++; } else { name->name = talloc_strdup(name, ""); - if (!name->name) goto failed; + if (!name->name) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } } if (dn->comp_num > cur && strcasecmp("type", dn->components[cur].name) == 0) { - name->type = strtoul((char *)dn->components[cur].value.data, NULL, 16); + name->type = strtoul((char *)dn->components[cur].value.data, NULL, 0); cur++; } else { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; goto failed; } - return name; + *_name = name; + return NT_STATUS_OK; failed: talloc_free(name); - return NULL; + return status; } /* decode the winsdb_addr("address") attribute: "172.31.1.1" or - "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z" + "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;" are valid records */ static BOOL winsdb_remove_version(struct wins_server *winssrv, uint64_t version) @@ -247,6 +257,7 @@ const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **a */ static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_CTX *mem_ctx, struct ldb_val *val) { + NTSTATUS status; struct winsdb_addr *addr; char *address; char *wins_owner; @@ -254,7 +265,10 @@ static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_ char *p; addr = talloc(mem_ctx, struct winsdb_addr); - if (!addr) return NULL; + if (!addr) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } address = (char *)val->data; @@ -264,52 +278,60 @@ static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_ addr->address = talloc_steal(addr, val->data); addr->wins_owner = rec->wins_owner; addr->expire_time = rec->expire_time; - return addr; + *_addr = addr; + return NT_STATUS_OK; } *p = '\0';p++; addr->address = talloc_strdup(addr, address); if (!addr->address) { - talloc_free(addr); - return NULL; + status = NT_STATUS_NO_MEMORY; + goto failed; } if (strncmp("winsOwner:", p, 10) != 0) { - /* invalid record */ - talloc_free(addr); - return NULL; + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto failed; } wins_owner = p + 10; p = strchr(wins_owner, ';'); if (!p) { - /* invalid record */ - talloc_free(addr); - return NULL; + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto failed; } *p = '\0';p++; addr->wins_owner = talloc_strdup(addr, wins_owner); if (!addr->wins_owner) { - talloc_free(addr); - return NULL; + status = NT_STATUS_NO_MEMORY; + goto failed; } if (strncmp("expireTime:", p, 11) != 0) { - /* invalid record */ - talloc_free(addr); - return NULL; + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto failed; } expire_time = p + 11; + p = strchr(expire_time, ';'); + if (!p) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto failed; + } + *p = '\0';p++; addr->expire_time = ldap_string_to_time(expire_time); - return addr; + *_addr = addr; + return NT_STATUS_OK; +failed: + talloc_free(addr); + return status; } /* encode the winsdb_addr("address") attribute like this: - "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z" + "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;" */ static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg, const char *attr_name, struct winsdb_addr *addr) @@ -317,7 +339,7 @@ static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message * struct ldb_val val; const char *str; - str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s", + str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s;", addr->address, addr->wins_owner, ldap_timestring(msg, addr->expire_time)); if (!str) return -1; @@ -435,25 +457,33 @@ const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **a /* load a WINS entry from the database */ -struct winsdb_record *winsdb_load(struct wins_server *winssrv, - struct nbt_name *name, TALLOC_CTX *mem_ctx) +NTSTATUS winsdb_lookup(struct ldb_context *wins_db, + struct nbt_name *name, + TALLOC_CTX *mem_ctx, + struct winsdb_record **_rec) { + NTSTATUS status; struct ldb_message **res = NULL; int ret; struct winsdb_record *rec; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); /* find the record in the WINS database */ - ret = ldb_search(winssrv->wins_db, winsdb_dn(tmp_ctx, name), LDB_SCOPE_BASE, + ret = ldb_search(wins_db, winsdb_dn(tmp_ctx, name), LDB_SCOPE_BASE, NULL, NULL, &res); if (res != NULL) { talloc_steal(tmp_ctx, res); } - if (ret != 1) goto failed; + if (ret == 0) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto failed; + } else if (ret != 1) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto failed; + } - rec = winsdb_record(res[0], tmp_ctx); - if (rec == NULL) goto failed; - rec->name = name; + status = winsdb_record(res[0], name, tmp_ctx, &rec); + if (!NT_STATUS_IS_OK(status)) goto failed; /* see if it has already expired */ if (rec->state == WINS_REC_ACTIVE && @@ -465,21 +495,31 @@ struct winsdb_record *winsdb_load(struct wins_server *winssrv, talloc_steal(mem_ctx, rec); talloc_free(tmp_ctx); - return rec; + *_rec = rec; + return NT_STATUS_OK; failed: talloc_free(tmp_ctx); - return NULL; + return status; } -struct winsdb_record *winsdb_record(struct ldb_message *msg, TALLOC_CTX *mem_ctx) +NTSTATUS winsdb_record(struct ldb_message *msg, struct nbt_name *name, TALLOC_CTX *mem_ctx, struct winsdb_record **_rec) { + NTSTATUS status; struct winsdb_record *rec; struct ldb_message_element *el; uint32_t i; rec = talloc(mem_ctx, struct winsdb_record); - if (rec == NULL) goto failed; + if (rec == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } + + if (!name) { + status = winsdb_nbt_name(rec, msg->dn, &name); + if (!NT_STATUS_IS_OK(status)) goto failed; + } /* parse it into a more convenient winsdb_record structure */ rec->name = name; @@ -494,21 +534,31 @@ struct winsdb_record *winsdb_record(struct ldb_message *msg, TALLOC_CTX *mem_ctx if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL; el = ldb_msg_find_element(msg, "address"); - if (el == NULL) goto failed; + if (el == NULL) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + goto failed; + } rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1); - if (rec->addresses == NULL) goto failed; + if (rec->addresses == NULL) { + status = NT_STATUS_NO_MEMORY; + goto failed; + } for (i=0;inum_values;i++) { - rec->addresses[i] = winsdb_addr_decode(rec, rec->addresses, &el->values[i]); - if (rec->addresses[i] == NULL) goto failed; + status = winsdb_addr_decode(rec, &el->values[i], rec->addresses, &rec->addresses[i]); + if (!NT_STATUS_IS_OK(status)) goto failed; } rec->addresses[i] = NULL; - return rec; + *_rec = rec; + return NT_STATUS_OK; failed: + if (NT_STATUS_EQUAL(NT_STATUS_INTERNAL_DB_CORRUPTION, status)) { + DEBUG(1,("winsdb_record: corrupted record: %s\n", ldb_dn_linearize(rec, msg->dn))); + } talloc_free(rec); - return NULL; + return status; } /* diff --git a/source4/nbt_server/wins/winsserver.c b/source4/nbt_server/wins/winsserver.c index 37b59cdc7f5..d5043caa298 100644 --- a/source4/nbt_server/wins/winsserver.c +++ b/source4/nbt_server/wins/winsserver.c @@ -110,6 +110,7 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, struct nbt_name_packet *packet, const struct nbt_peer_socket *src) { + NTSTATUS status; struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbtd_interface); struct wins_server *winssrv = iface->nbtsrv->winssrv; @@ -125,10 +126,13 @@ static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock, goto done; } - rec = winsdb_load(winssrv, name, packet); - if (rec == NULL) { + 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); goto done; + } else if (!NT_STATUS_IS_OK(status)) { + rcode = NBT_RCODE_SVR; + goto done; } else if (rec->state != WINS_REC_ACTIVE) { winsdb_delete(winssrv, rec); rcode = wins_register_new(nbtsock, packet, src); @@ -182,6 +186,7 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, struct nbt_name_packet *packet, const struct nbt_peer_socket *src) { + NTSTATUS status; struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbtd_interface); struct wins_server *winssrv = iface->nbtsrv->winssrv; @@ -189,8 +194,8 @@ static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, struct winsdb_record *rec; const char **addresses; - rec = winsdb_load(winssrv, name, packet); - if (rec == NULL || rec->state != WINS_REC_ACTIVE) { + status = winsdb_lookup(winssrv->wins_db, name, packet, &rec); + if (!NT_STATUS_IS_OK(status) || rec->state != WINS_REC_ACTIVE) { nbtd_negative_name_query_reply(nbtsock, packet, src); return; } @@ -212,14 +217,15 @@ static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, struct nbt_name_packet *packet, const struct nbt_peer_socket *src) { + NTSTATUS status; struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, struct nbtd_interface); struct wins_server *winssrv = iface->nbtsrv->winssrv; struct nbt_name *name = &packet->questions[0].name; struct winsdb_record *rec; - rec = winsdb_load(winssrv, name, packet); - if (rec == NULL || + status = winsdb_lookup(winssrv->wins_db, name, packet, &rec); + if (!NT_STATUS_IS_OK(status) || rec->state != WINS_REC_ACTIVE || IS_GROUP_NAME(name, rec->nb_flags)) { goto done; diff --git a/source4/nbt_server/wins/winswack.c b/source4/nbt_server/wins/winswack.c index defa3ad09ab..64336992f6d 100644 --- a/source4/nbt_server/wins/winswack.c +++ b/source4/nbt_server/wins/winswack.c @@ -54,12 +54,13 @@ static void wins_wack_deny(struct wack_state *state) */ static void wins_wack_allow(struct wack_state *state) { + NTSTATUS status; uint32_t ttl; time_t now = time(NULL); struct winsdb_record *rec = state->rec, *rec2; - rec2 = winsdb_load(state->winssrv, rec->name, state); - if (rec2 == NULL || rec2->version != rec->version) { + status = winsdb_lookup(state->winssrv->wins_db, rec->name, state, &rec2); + if (!NT_STATUS_IS_OK(status) || 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); diff --git a/source4/wrepl_server/wrepl_in_call.c b/source4/wrepl_server/wrepl_in_call.c index ab86aa209f5..4472a0fede2 100644 --- a/source4/wrepl_server/wrepl_in_call.c +++ b/source4/wrepl_server/wrepl_in_call.c @@ -263,8 +263,8 @@ static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call) return NT_STATUS_OK; } - filter = talloc_asprintf(call, "(&(winsOwner=%s)(objectClass=wins)(active=1)(version>=%llu)(version<=%llu))", - owner->owner.address, owner_in->min_version, owner_in->max_version); + filter = talloc_asprintf(call, "(&(winsOwner=%s)(objectClass=winsRecord)(state>=%u)(versionID>=%llu)(versionID<=%llu))", + owner->owner.address, WINS_REC_ACTIVE, owner_in->min_version, owner_in->max_version); NT_STATUS_HAVE_NO_MEMORY(filter); ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, filter, NULL, &res); if (res != NULL) { @@ -277,13 +277,8 @@ static NTSTATUS wreplsrv_in_send_request(struct wreplsrv_in_call *call) NT_STATUS_HAVE_NO_MEMORY(names); for (i=0; i < ret; i++) { - rec = winsdb_record(res[i], call); - NT_STATUS_HAVE_NO_MEMORY(rec); - - rec->name = winsdb_nbt_name(names, res[i]->dn); - if (!rec->name) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } + status = winsdb_record(res[i], NULL, call, &rec); + NT_STATUS_NOT_OK_RETURN(status); status = wreplsrv_record2wins_name(names, &names[i], rec); NT_STATUS_NOT_OK_RETURN(status); diff --git a/source4/wrepl_server/wrepl_server.c b/source4/wrepl_server/wrepl_server.c index 866090f4005..dd49b37d78b 100644 --- a/source4/wrepl_server/wrepl_server.c +++ b/source4/wrepl_server/wrepl_server.c @@ -205,13 +205,13 @@ static NTSTATUS wreplsrv_load_table(struct wreplsrv_service *service) uint64_t version; const char * const attrs[] = { "winsOwner", - "version", + "versionID", NULL }; /* find the record in the WINS database */ ret = ldb_search(service->wins_db, NULL, LDB_SCOPE_SUBTREE, - "(objectClass=wins)", attrs, &res); + "(objectClass=winsRecord)", attrs, &res); if (res != NULL) { talloc_steal(tmp_ctx, res); } @@ -221,7 +221,7 @@ static NTSTATUS wreplsrv_load_table(struct wreplsrv_service *service) for (i=0; i < ret; i++) { wins_owner = ldb_msg_find_string(res[i], "winsOwner", NULL); - version = ldb_msg_find_uint64(res[i], "version", 0); + version = ldb_msg_find_uint64(res[i], "versionID", 0); if (wins_owner) { status = wreplsrv_add_table(service,