2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/wins/winsdb.h"
26 #include "lib/ldb/include/ldb.h"
27 #include "lib/ldb/include/ldb_errors.h"
29 #include "system/time.h"
32 return the new maxVersion and save it
34 static uint64_t winsdb_allocate_version(struct wins_server *winssrv)
37 struct ldb_context *ldb = winssrv->wins_db;
39 struct ldb_message **res = NULL;
40 struct ldb_message *msg = NULL;
41 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
42 uint64_t maxVersion = 0;
44 dn = ldb_dn_explode(tmp_ctx, "CN=VERSION");
47 ret |= ldb_msg_add_string(msg, "objectClass", "winsEntry");
48 ret |= ldb_msg_add_fmt(msg, "minVersion", "%llu", winssrv->min_version);
49 ret |= ldb_msg_add_fmt(msg, "maxVersion", "%llu", winssrv->max_version);
50 if (ret != 0) goto failed;
53 maxVersion = ldb_msg_find_uint64(res[0], "maxVersion", 0);
57 msg = ldb_msg_new(tmp_ctx);
58 if (!msg) goto failed;
62 ret = ldb_msg_add_empty(ldb, msg, "maxVersion", LDB_FLAG_MOD_REPLACE);
63 if (ret != 0) goto failed;
64 ret = ldb_msg_add_fmt(ldb, msg, "maxVersion", "%llu", maxVersion);
65 if (ret != 0) goto failed;
67 ret = ldb_modify(ldb, msg);
68 if (ret != 0) ret = ldb_add(ldb, msg);
69 if (ret != 0) goto failed;
80 return a DN for a nbt_name
82 static struct ldb_dn *winsdb_dn(TALLOC_CTX *mem_ctx, struct nbt_name *name)
86 dn = ldb_dn_string_compose(mem_ctx, NULL, "type=%02x", name->type);
87 if (dn && name->name && *name->name) {
88 dn = ldb_dn_string_compose(mem_ctx, dn, "name=%s", name->name);
90 if (dn && name->scope && *name->scope) {
91 dn = ldb_dn_string_compose(mem_ctx, dn, "scope=%s", name->scope);
97 decode the winsdb_addr("address") attribute:
99 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
102 static BOOL winsdb_remove_version(struct wins_server *winssrv, uint64_t version)
104 if (version == winssrv->min_version) {
105 winssrv->min_version++;
106 return winsdb_save_version(winssrv);
113 encode the winsdb_addr("address") attribute like this:
114 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
116 static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
117 const char *attr_name, struct winsdb_addr *addr)
122 dn = ldb_dn_string_compose(mem_ctx, NULL, "type=%02x", name->type);
124 addresses[len]->address = talloc_strdup(addresses[len], address);
125 if (!addresses[len]->address) {
126 talloc_free(addresses);
130 addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
131 if (!addresses[len]->wins_owner) {
132 talloc_free(addresses);
136 addresses[len]->expire_time = expire_time;
138 addresses[len+1] = NULL;
143 void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
147 for (i=0; addresses[i]; i++) {
148 if (strcmp(addresses[i]->address, address) == 0) {
152 if (!addresses[i]) return;
154 for (; addresses[i]; i++) {
155 addresses[i] = addresses[i+1];
161 struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
165 for (i=0; addresses[i]; i++) {
166 if (strcmp(addresses[i]->address, address) == 0) {
174 size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
177 for (i=0; addresses[i]; i++);
181 const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
183 size_t len = winsdb_addr_list_length(addresses);
184 const char **str_list;
187 str_list = talloc_array(mem_ctx, const char *, len + 1);
188 if (!str_list) return NULL;
190 for (i=0; i < len; i++) {
191 str_list[i] = talloc_strdup(str_list, addresses[i]->address);
193 talloc_free(str_list);
198 str_list[len] = NULL;
203 decode the winsdb_addr("address") attribute:
205 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
208 static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_CTX *mem_ctx, struct ldb_val *val)
210 struct winsdb_addr *addr;
216 addr = talloc(mem_ctx, struct winsdb_addr);
217 if (!addr) return NULL;
219 address = (char *)val->data;
221 p = strchr(address, ';');
223 /* support old entries, with only the address */
224 addr->address = talloc_steal(addr, val->data);
225 addr->wins_owner = rec->wins_owner;
226 addr->expire_time = rec->expire_time;
231 addr->address = talloc_strdup(addr, address);
232 if (!addr->address) {
237 if (strncmp("winsOwner:", p, 10) != 0) {
243 p = strchr(wins_owner, ';');
251 addr->wins_owner = talloc_strdup(addr, wins_owner);
252 if (!addr->wins_owner) {
257 if (strncmp("expireTime:", p, 11) != 0) {
263 expire_time = p + 11;
265 addr->expire_time = ldap_string_to_time(expire_time);
271 encode the winsdb_addr("address") attribute like this:
272 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
274 static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
275 const char *attr_name, struct winsdb_addr *addr)
280 str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s",
281 addr->address, addr->wins_owner,
282 ldap_timestring(msg, addr->expire_time));
285 val.data = discard_const_p(uint8_t, str);
286 val.length = strlen(str);
288 return ldb_msg_add_value(ldb, msg, attr_name, &val);
291 struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
293 struct winsdb_addr **addresses;
295 addresses = talloc_array(mem_ctx, struct winsdb_addr *, 1);
296 if (!addresses) return NULL;
303 struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const char *address,
304 const char *wins_owner, time_t expire_time)
306 size_t len = winsdb_addr_list_length(addresses);
308 addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2);
309 if (!addresses) return NULL;
311 addresses[len] = talloc(addresses, struct winsdb_addr);
312 if (!addresses[len]) {
313 talloc_free(addresses);
317 addresses[len]->address = talloc_strdup(addresses[len], address);
318 if (!addresses[len]->address) {
319 talloc_free(addresses);
323 addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
324 if (!addresses[len]->wins_owner) {
325 talloc_free(addresses);
329 addresses[len]->expire_time = expire_time;
331 addresses[len+1] = NULL;
336 void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
340 for (i=0; addresses[i]; i++) {
341 if (strcmp(addresses[i]->address, address) == 0) {
345 if (!addresses[i]) return;
347 for (; addresses[i]; i++) {
348 addresses[i] = addresses[i+1];
354 struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
358 for (i=0; addresses[i]; i++) {
359 if (strcmp(addresses[i]->address, address) == 0) {
367 size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
370 for (i=0; addresses[i]; i++);
374 const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
376 size_t len = winsdb_addr_list_length(addresses);
377 const char **str_list;
380 str_list = talloc_array(mem_ctx, const char *, len + 1);
381 if (!str_list) return NULL;
383 for (i=0; i < len; i++) {
384 str_list[i] = talloc_strdup(str_list, addresses[i]->address);
386 talloc_free(str_list);
391 str_list[len] = NULL;
396 load a WINS entry from the database
398 struct winsdb_record *winsdb_load(struct wins_server *winssrv,
399 struct nbt_name *name, TALLOC_CTX *mem_ctx)
401 struct ldb_message **res = NULL;
403 struct winsdb_record *rec;
404 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
406 /* find the record in the WINS database */
407 ret = ldb_search(winssrv->wins_db, winsdb_dn(tmp_ctx, name), LDB_SCOPE_BASE,
410 talloc_steal(tmp_ctx, res);
412 if (ret != 1) goto failed;
414 rec = winsdb_record(res[0], tmp_ctx);
415 if (rec == NULL) goto failed;
418 /* see if it has already expired */
419 if (rec->state == WINS_REC_ACTIVE &&
420 rec->expire_time <= time(NULL)) {
421 DEBUG(5,("WINS: expiring name %s (expired at %s)\n",
422 nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time)));
423 rec->state = WINS_REC_RELEASED;
426 talloc_steal(mem_ctx, rec);
427 talloc_free(tmp_ctx);
431 talloc_free(tmp_ctx);
435 struct winsdb_record *winsdb_record(struct ldb_message *msg, TALLOC_CTX *mem_ctx)
437 struct winsdb_record *rec;
438 struct ldb_message_element *el;
441 rec = talloc(mem_ctx, struct winsdb_record);
442 if (rec == NULL) goto failed;
444 /* parse it into a more convenient winsdb_record structure */
446 rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED);
447 rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0);
448 rec->expire_time = ldb_string_to_time(ldb_msg_find_string(res[0], "expires", NULL));
449 rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL);
450 rec->version = ldb_msg_find_uint64(res[0], "version", 0);
451 talloc_steal(rec, rec->wins_owner);
452 talloc_steal(rec, rec->registered_by);
454 if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL;
456 el = ldb_msg_find_element(msg, "address");
457 if (el == NULL) goto failed;
459 rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1);
460 if (rec->addresses == NULL) goto failed;
462 for (i=0;i<el->num_values;i++) {
463 rec->addresses[i] = winsdb_addr_decode(rec, rec->addresses, &el->values[i]);
464 if (rec->addresses[i] == NULL) goto failed;
466 rec->addresses[i] = NULL;
475 form a ldb_message from a winsdb_record
477 struct ldb_message *winsdb_message(struct ldb_context *ldb,
478 struct winsdb_record *rec, TALLOC_CTX *mem_ctx)
481 struct ldb_message *msg = ldb_msg_new(mem_ctx);
482 if (msg == NULL) goto failed;
484 msg->dn = winsdb_dn(msg, rec->name);
485 if (msg->dn == NULL) goto failed;
486 ret |= ldb_msg_add_fmt(msg, "objectClass", "wins");
487 ret |= ldb_msg_add_fmt(msg, "active", "%u", rec->state);
488 ret |= ldb_msg_add_fmt(msg, "nbFlags", "0x%04x", rec->nb_flags);
489 ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by);
490 ret |= ldb_msg_add_string(msg, "expires",
491 ldb_timestring(msg, rec->expire_time));
492 ret |= ldb_msg_add_fmt(msg, "version", "%llu", rec->version);
493 for (i=0;rec->addresses[i];i++) {
494 ret |= ldb_msg_add_string(msg, "address", rec->addresses[i]);
496 if (ret != 0) goto failed;
505 save a WINS record into the database
507 uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec)
509 struct ldb_context *ldb = winssrv->wins_db;
510 struct ldb_message *msg;
511 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
516 trans = ldb_transaction_start(ldb);
517 if (trans != LDB_SUCCESS) goto failed;
519 rec->version = winsdb_allocate_version(winssrv);
520 if (rec->version == 0) goto failed;
522 msg = winsdb_message(winssrv->wins_db, rec, tmp_ctx);
523 if (msg == NULL) goto failed;
524 ret = ldb_add(ldb, msg);
525 if (ret != 0) goto failed;
527 trans = ldb_transaction_commit(ldb);
528 if (trans != LDB_SUCCESS) goto failed;
530 talloc_free(tmp_ctx);
534 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
535 talloc_free(tmp_ctx);
536 return NBT_RCODE_SVR;
541 modify a WINS record in the database
543 uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec)
545 struct ldb_context *ldb = winssrv->wins_db;
546 struct ldb_message *msg;
547 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
552 trans = ldb_transaction_start(ldb);
553 if (trans != LDB_SUCCESS) goto failed;
555 rec->version = winsdb_allocate_version(winssrv);
556 if (rec->version == 0) goto failed;
557 rec->wins_owner = WINSDB_OWNER_LOCAL;
559 msg = winsdb_message(winssrv->wins_db, rec, tmp_ctx);
560 if (msg == NULL) goto failed;
562 for (i=0;i<msg->num_elements;i++) {
563 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
566 ret = ldb_modify(ldb, msg);
567 if (ret != 0) goto failed;
569 trans = ldb_transaction_commit(ldb);
570 if (trans != LDB_SUCCESS) goto failed;
572 talloc_free(tmp_ctx);
576 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
577 talloc_free(tmp_ctx);
578 return NBT_RCODE_SVR;
583 delete a WINS record from the database
585 uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec)
587 struct ldb_context *ldb = winssrv->wins_db;
588 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
589 const struct ldb_dn *dn;
593 trans = ldb_transaction_start(ldb);
594 if (trans != LDB_SUCCESS) goto failed;
596 if(!winsdb_remove_version(winssrv, rec->version))
599 dn = winsdb_dn(tmp_ctx, rec->name);
600 if (dn == NULL) goto failed;
602 ret = ldb_delete(ldb, dn);
603 if (ret != 0) goto failed;
605 trans = ldb_transaction_commit(ldb);
606 if (trans != LDB_SUCCESS) goto failed;
608 talloc_free(tmp_ctx);
612 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
613 talloc_free(tmp_ctx);
614 return NBT_RCODE_SVR;
617 struct ldb_context *winsdb_connect(TALLOC_CTX *mem_ctx)
619 return ldb_wrap_connect(mem_ctx, lp_wins_url(), 0, NULL);