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 allocate a new version id for a record
82 static uint64_t winsdb_allocate_version(struct wins_server *winssrv)
84 winssrv->max_version++;
85 if (!winsdb_save_version(winssrv)) {
88 return winssrv->max_version;
94 static BOOL winsdb_remove_version(struct wins_server *winssrv, uint64_t version)
96 if (version == winssrv->min_version) {
97 winssrv->min_version++;
98 return winsdb_save_version(winssrv);
106 return a DN for a nbt_name
108 static struct ldb_dn *winsdb_dn(TALLOC_CTX *mem_ctx, struct nbt_name *name)
112 dn = ldb_dn_string_compose(mem_ctx, NULL, "type=%02x", name->type);
113 if (dn && name->name && *name->name) {
114 dn = ldb_dn_string_compose(mem_ctx, dn, "name=%s", name->name);
116 if (dn && name->scope && *name->scope) {
117 dn = ldb_dn_string_compose(mem_ctx, dn, "scope=%s", name->scope);
123 decode the winsdb_addr("address") attribute:
125 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
128 static struct winsdb_addr *winsdb_addr_decode(struct winsdb_record *rec, TALLOC_CTX *mem_ctx, struct ldb_val *val)
130 struct winsdb_addr *addr;
136 addr = talloc(mem_ctx, struct winsdb_addr);
137 if (!addr) return NULL;
139 address = (char *)val->data;
141 p = strchr(address, ';');
143 /* support old entries, with only the address */
144 addr->address = talloc_steal(addr, val->data);
145 addr->wins_owner = rec->wins_owner;
146 addr->expire_time = rec->expire_time;
151 addr->address = talloc_strdup(addr, address);
152 if (!addr->address) {
157 if (strncmp("winsOwner:", p, 10) != 0) {
163 p = strchr(wins_owner, ';');
171 addr->wins_owner = talloc_strdup(addr, wins_owner);
172 if (!addr->wins_owner) {
177 if (strncmp("expireTime:", p, 11) != 0) {
183 expire_time = p + 11;
185 addr->expire_time = ldap_string_to_time(expire_time);
191 encode the winsdb_addr("address") attribute like this:
192 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z"
194 static int ldb_msg_add_winsdb_addr(struct ldb_context *ldb, struct ldb_message *msg,
195 const char *attr_name, struct winsdb_addr *addr)
200 str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s",
201 addr->address, addr->wins_owner,
202 ldap_timestring(msg, addr->expire_time));
205 val.data = discard_const_p(uint8_t, str);
206 val.length = strlen(str);
208 return ldb_msg_add_value(ldb, msg, attr_name, &val);
211 struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
213 struct winsdb_addr **addresses;
215 addresses = talloc_array(mem_ctx, struct winsdb_addr *, 1);
216 if (!addresses) return NULL;
223 struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const char *address,
224 const char *wins_owner, time_t expire_time)
226 size_t len = winsdb_addr_list_length(addresses);
228 addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2);
229 if (!addresses) return NULL;
231 addresses[len] = talloc(addresses, struct winsdb_addr);
232 if (!addresses[len]) {
233 talloc_free(addresses);
237 addresses[len]->address = talloc_strdup(addresses[len], address);
238 if (!addresses[len]->address) {
239 talloc_free(addresses);
243 addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
244 if (!addresses[len]->wins_owner) {
245 talloc_free(addresses);
249 addresses[len]->expire_time = expire_time;
251 addresses[len+1] = NULL;
256 void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
260 for (i=0; addresses[i]; i++) {
261 if (strcmp(addresses[i]->address, address) == 0) {
265 if (!addresses[i]) return;
267 for (; addresses[i]; i++) {
268 addresses[i] = addresses[i+1];
274 struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
278 for (i=0; addresses[i]; i++) {
279 if (strcmp(addresses[i]->address, address) == 0) {
287 size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
290 for (i=0; addresses[i]; i++);
294 const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
296 size_t len = winsdb_addr_list_length(addresses);
297 const char **str_list;
300 str_list = talloc_array(mem_ctx, const char *, len + 1);
301 if (!str_list) return NULL;
303 for (i=0; i < len; i++) {
304 str_list[i] = talloc_strdup(str_list, addresses[i]->address);
306 talloc_free(str_list);
311 str_list[len] = NULL;
316 load a WINS entry from the database
318 struct winsdb_record *winsdb_load(struct wins_server *winssrv,
319 struct nbt_name *name, TALLOC_CTX *mem_ctx)
321 struct ldb_message **res = NULL;
323 struct winsdb_record *rec;
324 struct ldb_message_element *el;
325 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
328 /* find the record in the WINS database */
329 ret = ldb_search(winssrv->wins_db, winsdb_dn(tmp_ctx, name), LDB_SCOPE_BASE,
332 talloc_steal(tmp_ctx, res);
334 if (ret != 1) goto failed;
336 rec = talloc(tmp_ctx, struct winsdb_record);
337 if (rec == NULL) goto failed;
339 /* parse it into a more convenient winsdb_record structure */
341 rec->state = ldb_msg_find_int(res[0], "active", WINS_REC_RELEASED);
342 rec->nb_flags = ldb_msg_find_int(res[0], "nbFlags", 0);
343 rec->expire_time = ldb_string_to_time(ldb_msg_find_string(res[0], "expires", NULL));
344 rec->registered_by = ldb_msg_find_string(res[0], "registeredBy", NULL);
345 rec->version = ldb_msg_find_uint64(res[0], "version", 0);
346 talloc_steal(rec, rec->wins_owner);
347 talloc_steal(rec, rec->registered_by);
349 if (!rec->wins_owner) rec->wins_owner = WINSDB_OWNER_LOCAL;
351 el = ldb_msg_find_element(res[0], "address");
352 if (el == NULL) goto failed;
354 rec->addresses = talloc_array(rec, struct winsdb_addr *, el->num_values+1);
355 if (rec->addresses == NULL) goto failed;
357 for (i=0;i<el->num_values;i++) {
358 rec->addresses[i] = winsdb_addr_decode(rec, rec->addresses, &el->values[i]);
359 if (rec->addresses[i] == NULL) goto failed;
361 rec->addresses[i] = NULL;
363 /* see if it has already expired */
364 if (rec->state == WINS_REC_ACTIVE &&
365 rec->expire_time <= time(NULL)) {
366 DEBUG(5,("WINS: expiring name %s (expired at %s)\n",
367 nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time)));
368 rec->state = WINS_REC_RELEASED;
371 talloc_steal(mem_ctx, rec);
372 talloc_free(tmp_ctx);
376 talloc_free(tmp_ctx);
382 form a ldb_message from a winsdb_record
384 static struct ldb_message *winsdb_message(struct wins_server *winssrv,
385 struct winsdb_record *rec, TALLOC_CTX *mem_ctx)
388 struct ldb_message *msg = ldb_msg_new(mem_ctx);
389 if (msg == NULL) goto failed;
391 msg->dn = winsdb_dn(msg, rec->name);
392 if (msg->dn == NULL) goto failed;
393 ret |= ldb_msg_add_fmt(msg, "objectClass", "wins");
394 ret |= ldb_msg_add_fmt(msg, "active", "%u", rec->state);
395 ret |= ldb_msg_add_fmt(msg, "nbFlags", "0x%04x", rec->nb_flags);
396 ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by);
397 ret |= ldb_msg_add_string(msg, "expires",
398 ldb_timestring(msg, rec->expire_time));
399 ret |= ldb_msg_add_fmt(msg, "version", "%llu", rec->version);
400 for (i=0;rec->addresses[i];i++) {
401 ret |= ldb_msg_add_string(msg, "address", rec->addresses[i]);
403 if (ret != 0) goto failed;
412 save a WINS record into the database
414 uint8_t winsdb_add(struct wins_server *winssrv, struct winsdb_record *rec)
416 struct ldb_context *ldb = winssrv->wins_db;
417 struct ldb_message *msg;
418 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
423 trans = ldb_transaction_start(ldb);
424 if (trans != LDB_SUCCESS) goto failed;
426 rec->version = winsdb_allocate_version(winssrv);
427 if (rec->version == 0) goto failed;
429 msg = winsdb_message(winssrv, rec, tmp_ctx);
430 if (msg == NULL) goto failed;
431 ret = ldb_add(ldb, msg);
432 if (ret != 0) goto failed;
434 trans = ldb_transaction_commit(ldb);
435 if (trans != LDB_SUCCESS) goto failed;
437 talloc_free(tmp_ctx);
441 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
442 talloc_free(tmp_ctx);
443 return NBT_RCODE_SVR;
448 modify a WINS record in the database
450 uint8_t winsdb_modify(struct wins_server *winssrv, struct winsdb_record *rec)
452 struct ldb_context *ldb = winssrv->wins_db;
453 struct ldb_message *msg;
454 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
459 trans = ldb_transaction_start(ldb);
460 if (trans != LDB_SUCCESS) goto failed;
462 rec->version = winsdb_allocate_version(winssrv);
463 if (rec->version == 0) goto failed;
464 rec->wins_owner = WINSDB_OWNER_LOCAL;
466 msg = winsdb_message(winssrv, rec, tmp_ctx);
467 if (msg == NULL) goto failed;
469 for (i=0;i<msg->num_elements;i++) {
470 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
473 ret = ldb_modify(ldb, msg);
474 if (ret != 0) goto failed;
476 trans = ldb_transaction_commit(ldb);
477 if (trans != LDB_SUCCESS) goto failed;
479 talloc_free(tmp_ctx);
483 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
484 talloc_free(tmp_ctx);
485 return NBT_RCODE_SVR;
490 delete a WINS record from the database
492 uint8_t winsdb_delete(struct wins_server *winssrv, struct winsdb_record *rec)
494 struct ldb_context *ldb = winssrv->wins_db;
495 TALLOC_CTX *tmp_ctx = talloc_new(winssrv);
496 const struct ldb_dn *dn;
500 trans = ldb_transaction_start(ldb);
501 if (trans != LDB_SUCCESS) goto failed;
503 if(!winsdb_remove_version(winssrv, rec->version))
506 dn = winsdb_dn(tmp_ctx, rec->name);
507 if (dn == NULL) goto failed;
509 ret = ldb_delete(ldb, dn);
510 if (ret != 0) goto failed;
512 trans = ldb_transaction_commit(ldb);
513 if (trans != LDB_SUCCESS) goto failed;
515 talloc_free(tmp_ctx);
519 if (trans == LDB_SUCCESS) ldb_transaction_cancel(ldb);
520 talloc_free(tmp_ctx);
521 return NBT_RCODE_SVR;
524 struct ldb_context *winsdb_connect(TALLOC_CTX *mem_ctx)
526 return ldb_wrap_connect(mem_ctx, lp_wins_url(), 0, NULL);