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);
96 struct nbt_name *winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
98 struct nbt_name *name;
101 name = talloc(mem_ctx, struct nbt_name);
102 if (!name) goto failed;
104 if (dn->comp_num > 3) {
108 if (dn->comp_num > cur && strcasecmp("scope", dn->components[cur].name) == 0) {
109 name->scope = talloc_steal(name, dn->components[cur].value.data);
115 if (dn->comp_num > cur && strcasecmp("name", dn->components[cur].name) == 0) {
116 name->name = talloc_steal(name, dn->components[cur].value.data);
119 name->name = talloc_strdup(name, "");
120 if (!name->name) goto failed;
123 if (dn->comp_num > cur && strcasecmp("type", dn->components[cur].name) == 0) {
124 name->type = strtoul((char *)dn->components[cur].value.data, NULL, 16);
137 decode the winsdb_addr("address") attribute:
139 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
142 static BOOL winsdb_remove_version(struct wins_server *winssrv, uint64_t version)
144 if (version == winssrv->min_version) {
145 winssrv->min_version++;
146 return winsdb_save_version(winssrv);
153 encode the winsdb_addr("address") attribute like this:
154 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
156 static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
157 const char *attr_name, struct winsdb_addr *addr)
162 dn = ldb_dn_string_compose(mem_ctx, NULL, "type=%02x", name->type);
164 addresses[len]->address = talloc_strdup(addresses[len], address);
165 if (!addresses[len]->address) {
166 talloc_free(addresses);
170 addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
171 if (!addresses[len]->wins_owner) {
172 talloc_free(addresses);
176 addresses[len]->expire_time = expire_time;
178 addresses[len+1] = NULL;
183 void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
187 for (i=0; addresses[i]; i++) {
188 if (strcmp(addresses[i]->address, address) == 0) {
192 if (!addresses[i]) return;
194 for (; addresses[i]; i++) {
195 addresses[i] = addresses[i+1];
201 struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
205 for (i=0; addresses[i]; i++) {
206 if (strcmp(addresses[i]->address, address) == 0) {
214 size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
217 for (i=0; addresses[i]; i++);
221 const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
223 size_t len = winsdb_addr_list_length(addresses);
224 const char **str_list;
227 str_list = talloc_array(mem_ctx, const char *, len + 1);
228 if (!str_list) return NULL;
230 for (i=0; i < len; i++) {
231 str_list[i] = talloc_strdup(str_list, addresses[i]->address);
233 talloc_free(str_list);
238 str_list[len] = NULL;
243 decode the winsdb_addr("address") attribute:
245 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
248 static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_CTX *mem_ctx, struct ldb_val *val)
250 struct winsdb_addr *addr;
256 addr = talloc(mem_ctx, struct winsdb_addr);
257 if (!addr) return NULL;
259 address = (char *)val->data;
261 p = strchr(address, ';');
263 /* support old entries, with only the address */
264 addr->address = talloc_steal(addr, val->data);
265 addr->wins_owner = rec->wins_owner;
266 addr->expire_time = rec->expire_time;
271 addr->address = talloc_strdup(addr, address);
272 if (!addr->address) {
277 if (strncmp("winsOwner:", p, 10) != 0) {
283 p = strchr(wins_owner, ';');
291 addr->wins_owner = talloc_strdup(addr, wins_owner);
292 if (!addr->wins_owner) {
297 if (strncmp("expireTime:", p, 11) != 0) {
303 expire_time = p + 11;
305 addr->expire_time = ldap_string_to_time(expire_time);
311 encode the winsdb_addr("address") attribute like this:
312 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
314 static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
315 const char *attr_name, struct winsdb_addr *addr)
320 str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s",
321 addr->address, addr->wins_owner,
322 ldap_timestring(msg, addr->expire_time));
325 val.data = discard_const_p(uint8_t, str);
326 val.length = strlen(str);
328 return ldb_msg_add_value(ldb, msg, attr_name, &val);
331 struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
333 struct winsdb_addr **addresses;
335 addresses = talloc_array(mem_ctx, struct winsdb_addr *, 1);
336 if (!addresses) return NULL;
343 struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const char *address,
344 const char *wins_owner, time_t expire_time)
346 size_t len = winsdb_addr_list_length(addresses);
348 addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2);
349 if (!addresses) return NULL;
351 addresses[len] = talloc(addresses, struct winsdb_addr);
352 if (!addresses[len]) {
353 talloc_free(addresses);
357 addresses[len]->address = talloc_strdup(addresses[len], address);
358 if (!addresses[len]->address) {
359 talloc_free(addresses);
363 addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
364 if (!addresses[len]->wins_owner) {
365 talloc_free(addresses);
369 addresses[len]->expire_time = expire_time;
371 addresses[len+1] = NULL;
376 void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
380 for (i=0; addresses[i]; i++) {
381 if (strcmp(addresses[i]->address, address) == 0) {
385 if (!addresses[i]) return;
387 for (; addresses[i]; i++) {
388 addresses[i] = addresses[i+1];
394 struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
398 for (i=0; addresses[i]; i++) {
399 if (strcmp(addresses[i]->address, address) == 0) {
407 size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
410 for (i=0; addresses[i]; i++);
414 const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
416 size_t len = winsdb_addr_list_length(addresses);
417 const char **str_list;
420 str_list = talloc_array(mem_ctx, const char *, len + 1);
421 if (!str_list) return NULL;
423 for (i=0; i < len; i++) {
424 str_list[i] = talloc_strdup(str_list, addresses[i]->address);
426 talloc_free(str_list);
431 str_list[len] = NULL;
436 load a WINS entry from the database
438 struct winsdb_record *winsdb_load(struct wins_server *winssrv,
439 struct nbt_name *name, TALLOC_CTX *mem_ctx)
441 struct ldb_message **res = NULL;
443 struct winsdb_record *rec;
444 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
446 /* find the record in the WINS database */
447 ret = ldb_search(winssrv->wins_db, winsdb_dn(tmp_ctx, name), LDB_SCOPE_BASE,
450 talloc_steal(tmp_ctx, res);
452 if (ret != 1) goto failed;
454 rec = winsdb_record(res[0], tmp_ctx);
455 if (rec == NULL) goto failed;
458 /* see if it has already expired */
459 if (rec->state == WINS_REC_ACTIVE &&
460 rec->expire_time <= time(NULL)) {
461 DEBUG(5,("WINS: expiring name %s (expired at %s)\n",
462 nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time)));
463 rec->state = WINS_REC_RELEASED;
466 talloc_steal(mem_ctx, rec);
467 talloc_free(tmp_ctx);
471 talloc_free(tmp_ctx);
475 struct winsdb_record *winsdb_record(struct ldb_message *msg, TALLOC_CTX *mem_ctx)
477 struct winsdb_record *rec;
478 struct ldb_message_element *el;
481 rec = talloc(mem_ctx, struct winsdb_record);
482 if (rec == NULL) goto failed;
484 /* parse it into a more convenient winsdb_record structure */
486 rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED);
487 rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0);
488 rec->expire_time = ldb_string_to_time(ldb_msg_find_string(res[0], "expires", NULL));
489 rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL);
490 rec->version = ldb_msg_find_uint64(res[0], "version", 0);
491 talloc_steal(rec, rec->wins_owner);
492 talloc_steal(rec, rec->registered_by);
494 if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL;
496 el = ldb_msg_find_element(msg, "address");
497 if (el == NULL) goto failed;
499 rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1);
500 if (rec->addresses == NULL) goto failed;
502 for (i=0;i<el->num_values;i++) {
503 rec->addresses[i] = winsdb_addr_decode(rec, rec->addresses, &el->values[i]);
504 if (rec->addresses[i] == NULL) goto failed;
506 rec->addresses[i] = NULL;
515 form a ldb_message from a winsdb_record
517 struct ldb_message *winsdb_message(struct ldb_context *ldb,
518 struct winsdb_record *rec, TALLOC_CTX *mem_ctx)
521 struct ldb_message *msg = ldb_msg_new(mem_ctx);
522 if (msg == NULL) goto failed;
524 msg->dn = winsdb_dn(msg, rec->name);
525 if (msg->dn == NULL) goto failed;
526 ret |= ldb_msg_add_fmt(msg, "objectClass", "wins");
527 ret |= ldb_msg_add_fmt(msg, "active", "%u", rec->state);
528 ret |= ldb_msg_add_fmt(msg, "nbFlags", "0x%04x", rec->nb_flags);
529 ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by);
530 ret |= ldb_msg_add_string(msg, "expires",
531 ldb_timestring(msg, rec->expire_time));
532 ret |= ldb_msg_add_fmt(msg, "version", "%llu", rec->version);
533 for (i=0;rec->addresses[i];i++) {
534 ret |= ldb_msg_add_string(msg, "address", rec->addresses[i]);
536 if (ret != 0) goto failed;
545 save a WINS record into the database
547 uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec)
549 struct ldb_context *ldb = winssrv->wins_db;
550 struct ldb_message *msg;
551 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
556 trans = ldb_transaction_start(ldb);
557 if (trans != LDB_SUCCESS) goto failed;
559 rec->version = winsdb_allocate_version(winssrv);
560 if (rec->version == 0) goto failed;
562 msg = winsdb_message(winssrv->wins_db, rec, tmp_ctx);
563 if (msg == NULL) goto failed;
564 ret = ldb_add(ldb, msg);
565 if (ret != 0) goto failed;
567 trans = ldb_transaction_commit(ldb);
568 if (trans != LDB_SUCCESS) goto failed;
570 talloc_free(tmp_ctx);
574 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
575 talloc_free(tmp_ctx);
576 return NBT_RCODE_SVR;
581 modify a WINS record in the database
583 uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec)
585 struct ldb_context *ldb = winssrv->wins_db;
586 struct ldb_message *msg;
587 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
592 trans = ldb_transaction_start(ldb);
593 if (trans != LDB_SUCCESS) goto failed;
595 rec->version = winsdb_allocate_version(winssrv);
596 if (rec->version == 0) goto failed;
597 rec->wins_owner = WINSDB_OWNER_LOCAL;
599 msg = winsdb_message(winssrv->wins_db, rec, tmp_ctx);
600 if (msg == NULL) goto failed;
602 for (i=0;i<msg->num_elements;i++) {
603 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
606 ret = ldb_modify(ldb, msg);
607 if (ret != 0) goto failed;
609 trans = ldb_transaction_commit(ldb);
610 if (trans != LDB_SUCCESS) goto failed;
612 talloc_free(tmp_ctx);
616 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
617 talloc_free(tmp_ctx);
618 return NBT_RCODE_SVR;
623 delete a WINS record from the database
625 uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec)
627 struct ldb_context *ldb = winssrv->wins_db;
628 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
629 const struct ldb_dn *dn;
633 trans = ldb_transaction_start(ldb);
634 if (trans != LDB_SUCCESS) goto failed;
636 if(!winsdb_remove_version(winssrv, rec->version))
639 dn = winsdb_dn(tmp_ctx, rec->name);
640 if (dn == NULL) goto failed;
642 ret = ldb_delete(ldb, dn);
643 if (ret != 0) goto failed;
645 trans = ldb_transaction_commit(ldb);
646 if (trans != LDB_SUCCESS) goto failed;
648 talloc_free(tmp_ctx);
652 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
653 talloc_free(tmp_ctx);
654 return NBT_RCODE_SVR;
657 struct ldb_context *winsdb_connect(TALLOC_CTX *mem_ctx)
659 return ldb_wrap_connect(mem_ctx, lp_wins_url(), 0, NULL);