r12755: check the return value of ldb_timestring(), as this fails,
[kai/samba.git] / source4 / nbt_server / wins / winsdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    WINS database routines
5
6    Copyright (C) Andrew Tridgell        2005
7    Copyright (C) Stefan Metzmacher      2005
8       
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "nbt_server/nbt_server.h"
26 #include "nbt_server/wins/winsdb.h"
27 #include "lib/ldb/include/ldb.h"
28 #include "lib/ldb/include/ldb_errors.h"
29 #include "system/time.h"
30 #include "auth/auth.h"
31
32 uint64_t winsdb_get_maxVersion(struct winsdb_handle *h)
33 {
34         int ret;
35         struct ldb_context *ldb = h->ldb;
36         struct ldb_dn *dn;
37         struct ldb_result *res = NULL;
38         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
39         uint64_t maxVersion = 0;
40
41         dn = ldb_dn_explode(tmp_ctx, "CN=VERSION");
42         if (!dn) goto failed;
43
44         /* find the record in the WINS database */
45         ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, 
46                          NULL, NULL, &res);
47         if (ret != LDB_SUCCESS) goto failed;
48         talloc_steal(tmp_ctx, res);
49         if (res->count > 1) goto failed;
50
51         if (res->count == 1) {
52                 maxVersion = ldb_msg_find_uint64(res->msgs[0], "maxVersion", 0);
53         }
54
55 failed:
56         talloc_free(tmp_ctx);
57         return maxVersion;
58 }
59
60 /*
61  if newVersion == 0 return the old maxVersion + 1 and save it
62  if newVersion > 0 return MAX(oldMaxVersion, newMaxVersion) and save it
63 */
64 uint64_t winsdb_set_maxVersion(struct winsdb_handle *h, uint64_t newMaxVersion)
65 {
66         int trans;
67         int ret;
68         struct ldb_dn *dn;
69         struct ldb_result *res = NULL;
70         struct ldb_message *msg = NULL;
71         struct ldb_context *wins_db = h->ldb;
72         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
73         uint64_t oldMaxVersion = 0;
74
75         trans = ldb_transaction_start(wins_db);
76         if (trans != LDB_SUCCESS) goto failed;
77
78         dn = ldb_dn_explode(tmp_ctx, "CN=VERSION");
79         if (!dn) goto failed;
80
81         /* find the record in the WINS database */
82         ret = ldb_search(wins_db, dn, LDB_SCOPE_BASE, NULL, NULL, &res);
83
84         if (ret != LDB_SUCCESS) goto failed;
85         if (res->count > 1) goto failed;
86
87         talloc_steal(tmp_ctx, res);
88
89         if (res->count == 1) {
90                 oldMaxVersion = ldb_msg_find_uint64(res->msgs[0], "maxVersion", 0);
91         }
92
93         if (newMaxVersion == 0) {
94                 newMaxVersion = oldMaxVersion + 1;
95         } else {
96                 newMaxVersion = MAX(oldMaxVersion, newMaxVersion);
97         }
98
99         msg = ldb_msg_new(tmp_ctx);
100         if (!msg) goto failed;
101         msg->dn = dn;
102
103
104         ret = ldb_msg_add_empty(msg, "objectClass", LDB_FLAG_MOD_REPLACE);
105         if (ret != 0) goto failed;
106         ret = ldb_msg_add_string(msg, "objectClass", "winsMaxVersion");
107         if (ret != 0) goto failed;
108         ret = ldb_msg_add_empty(msg, "maxVersion", LDB_FLAG_MOD_REPLACE);
109         if (ret != 0) goto failed;
110         ret = ldb_msg_add_fmt(msg, "maxVersion", "%llu", (long long)newMaxVersion);
111         if (ret != 0) goto failed;
112
113         ret = ldb_modify(wins_db, msg);
114         if (ret != 0) ret = ldb_add(wins_db, msg);
115         if (ret != 0) goto failed;
116
117         trans = ldb_transaction_commit(wins_db);
118         if (trans != LDB_SUCCESS) goto failed;
119
120         talloc_free(tmp_ctx);
121         return newMaxVersion;
122
123 failed:
124         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
125         talloc_free(tmp_ctx);
126         return 0;
127 }
128
129 uint64_t winsdb_get_seqnumber(struct winsdb_handle *h)
130 {
131         int ret;
132         struct ldb_context *ldb = h->ldb;
133         struct ldb_dn *dn;
134         struct ldb_result *res = NULL;
135         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
136         uint64_t seqnumber = 0;
137
138         dn = ldb_dn_explode(tmp_ctx, "@BASEINFO");
139         if (!dn) goto failed;
140
141         /* find the record in the WINS database */
142         ret = ldb_search(ldb, dn, LDB_SCOPE_BASE, 
143                          NULL, NULL, &res);
144         if (ret != LDB_SUCCESS) goto failed;
145         talloc_steal(tmp_ctx, res);
146         if (res->count > 1) goto failed;
147
148         if (res->count == 1) {
149                 seqnumber = ldb_msg_find_uint64(res->msgs[0], "sequenceNumber", 0);
150         }
151
152 failed:
153         talloc_free(tmp_ctx);
154         return seqnumber;
155 }
156
157 /*
158   return a DN for a nbt_name
159 */
160 static struct ldb_dn *winsdb_dn(TALLOC_CTX *mem_ctx, struct nbt_name *name)
161 {
162         struct ldb_dn *dn;
163
164         dn = ldb_dn_string_compose(mem_ctx, NULL, "type=0x%02X", name->type);
165         if (dn && name->name && *name->name) {
166                 dn = ldb_dn_string_compose(mem_ctx, dn, "name=%s", name->name);
167         }
168         if (dn && name->scope && *name->scope) {
169                 dn = ldb_dn_string_compose(mem_ctx, dn, "scope=%s", name->scope);
170         }
171         return dn;
172 }
173
174 static NTSTATUS winsdb_nbt_name(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct nbt_name **_name)
175 {
176         NTSTATUS status;
177         struct nbt_name *name;
178         uint32_t cur = 0;
179
180         name = talloc(mem_ctx, struct nbt_name);
181         if (!name) {
182                 status = NT_STATUS_NO_MEMORY;
183                 goto failed;
184         }
185
186         if (dn->comp_num > 3) {
187                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
188                 goto failed;
189         }
190
191         if (dn->comp_num > cur && strcasecmp("scope", dn->components[cur].name) == 0) {
192                 name->scope     = talloc_steal(name, dn->components[cur].value.data);
193                 cur++;
194         } else {
195                 name->scope     = NULL;
196         }
197
198         if (dn->comp_num > cur && strcasecmp("name", dn->components[cur].name) == 0) {
199                 name->name      = talloc_steal(name, dn->components[cur].value.data);
200                 cur++;
201         } else {
202                 name->name      = talloc_strdup(name, "");
203                 if (!name->name) {
204                         status = NT_STATUS_NO_MEMORY;
205                         goto failed;
206                 }
207         }
208
209         if (dn->comp_num > cur && strcasecmp("type", dn->components[cur].name) == 0) {
210                 name->type      = strtoul((char *)dn->components[cur].value.data, NULL, 0);
211                 cur++;
212         } else {
213                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
214                 goto failed;
215         }
216
217         *_name = name;
218         return NT_STATUS_OK;
219 failed:
220         talloc_free(name);
221         return status;
222 }
223
224 /*
225  decode the winsdb_addr("address") attribute:
226  "172.31.1.1" or 
227  "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
228  are valid records
229 */
230 static NTSTATUS winsdb_addr_decode(struct winsdb_handle *h, struct winsdb_record *rec, struct ldb_val *val,
231                                    TALLOC_CTX *mem_ctx, struct winsdb_addr **_addr)
232 {
233         NTSTATUS status;
234         struct winsdb_addr *addr;
235         const char *address;
236         const char *wins_owner;
237         const char *expire_time;
238         char *p;
239
240         addr = talloc(mem_ctx, struct winsdb_addr);
241         if (!addr) {
242                 status = NT_STATUS_NO_MEMORY;
243                 goto failed;
244         }
245
246         address = (char *)val->data;
247
248         p = strchr(address, ';');
249         if (!p) {
250                 /* support old entries, with only the address */
251                 addr->address           = talloc_steal(addr, val->data);
252                 addr->wins_owner        = talloc_reference(addr, rec->wins_owner);
253                 if (!addr->wins_owner) {
254                         status = NT_STATUS_NO_MEMORY;
255                         goto failed;
256                 }
257                 addr->expire_time       = rec->expire_time;
258                 *_addr = addr;
259                 return NT_STATUS_OK;
260         }
261
262         *p = '\0';p++;
263         addr->address = talloc_strdup(addr, address);
264         if (!addr->address) {
265                 status = NT_STATUS_NO_MEMORY;
266                 goto failed;
267         }
268
269         if (strncmp("winsOwner:", p, 10) != 0) {
270                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
271                 goto failed;
272         }
273         wins_owner = p + 10;
274         p = strchr(wins_owner, ';');
275         if (!p) {
276                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
277                 goto failed;
278         }
279
280         *p = '\0';p++;
281         if (strcmp(wins_owner, "0.0.0.0") == 0) {
282                 wins_owner = h->local_owner;
283         }
284         addr->wins_owner = talloc_strdup(addr, wins_owner);
285         if (!addr->wins_owner) {
286                 status = NT_STATUS_NO_MEMORY;
287                 goto failed;
288         }
289
290         if (strncmp("expireTime:", p, 11) != 0) {
291                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
292                 goto failed;
293         }
294
295         expire_time = p + 11;
296         p = strchr(expire_time, ';');
297         if (!p) {
298                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
299                 goto failed;
300         }
301
302         *p = '\0';p++;
303         addr->expire_time = ldb_string_to_time(expire_time);
304
305         *_addr = addr;
306         return NT_STATUS_OK;
307 failed:
308         talloc_free(addr);
309         return status;
310 }
311
312 /*
313  encode the winsdb_addr("address") attribute like this:
314  "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
315 */
316 static int ldb_msg_add_winsdb_addr(struct ldb_message *msg, 
317                                    const char *attr_name, struct winsdb_addr *addr)
318 {
319         struct ldb_val val;
320         const char *str;
321         char *expire_time;
322
323         expire_time = ldb_timestring(msg, addr->expire_time);
324         if (!expire_time) return -1;
325         str = talloc_asprintf(msg, "%s;winsOwner:%s;expireTime:%s;",
326                               addr->address, addr->wins_owner,
327                               expire_time);
328         talloc_free(expire_time);
329         if (!str) return -1;
330
331         val.data = discard_const_p(uint8_t, str);
332         val.length = strlen(str);
333
334         return ldb_msg_add_value(msg, attr_name, &val);
335 }
336
337 struct winsdb_addr **winsdb_addr_list_make(TALLOC_CTX *mem_ctx)
338 {
339         struct winsdb_addr **addresses;
340
341         addresses = talloc_array(mem_ctx, struct winsdb_addr *, 1);
342         if (!addresses) return NULL;
343
344         addresses[0] = NULL;
345
346         return addresses;
347 }
348
349 struct winsdb_addr **winsdb_addr_list_add(struct winsdb_addr **addresses, const char *address,
350                                           const char *wins_owner, time_t expire_time)
351 {
352         size_t len = winsdb_addr_list_length(addresses);
353
354         addresses = talloc_realloc(addresses, addresses, struct winsdb_addr *, len + 2);
355         if (!addresses) return NULL;
356
357         addresses[len] = talloc(addresses, struct winsdb_addr);
358         if (!addresses[len]) {
359                 talloc_free(addresses);
360                 return NULL;
361         }
362
363         addresses[len]->address = talloc_strdup(addresses[len], address);
364         if (!addresses[len]->address) {
365                 talloc_free(addresses);
366                 return NULL;
367         }
368
369         addresses[len]->wins_owner = talloc_strdup(addresses[len], wins_owner);
370         if (!addresses[len]->wins_owner) {
371                 talloc_free(addresses);
372                 return NULL;
373         }
374
375         addresses[len]->expire_time = expire_time;
376
377         addresses[len+1] = NULL;
378
379         return addresses;
380 }
381
382 void winsdb_addr_list_remove(struct winsdb_addr **addresses, const char *address)
383 {
384         size_t i;
385
386         for (i=0; addresses[i]; i++) {
387                 if (strcmp(addresses[i]->address, address) == 0) {
388                         break;
389                 }
390         }
391         if (!addresses[i]) return;
392
393         for (; addresses[i]; i++) {
394                 addresses[i] = addresses[i+1];
395         }
396
397         return;
398 }
399
400 struct winsdb_addr *winsdb_addr_list_check(struct winsdb_addr **addresses, const char *address)
401 {
402         size_t i;
403
404         for (i=0; addresses[i]; i++) {
405                 if (strcmp(addresses[i]->address, address) == 0) {
406                         return addresses[i];
407                 }
408         }
409
410         return NULL;
411 }
412
413 size_t winsdb_addr_list_length(struct winsdb_addr **addresses)
414 {
415         size_t i;
416         for (i=0; addresses[i]; i++);
417         return i;
418 }
419
420 const char **winsdb_addr_string_list(TALLOC_CTX *mem_ctx, struct winsdb_addr **addresses)
421 {
422         size_t len = winsdb_addr_list_length(addresses);
423         const char **str_list=NULL;
424         size_t i;
425
426         for (i=0; i < len; i++) {
427                 str_list = str_list_add(str_list, addresses[i]->address);
428                 if (!str_list[i]) {
429                         return NULL;
430                 }
431         }
432         talloc_steal(mem_ctx, str_list);
433         return str_list;
434 }
435
436 /*
437   load a WINS entry from the database
438 */
439 NTSTATUS winsdb_lookup(struct winsdb_handle *h, 
440                        struct nbt_name *name,
441                        TALLOC_CTX *mem_ctx,
442                        struct winsdb_record **_rec)
443 {
444         NTSTATUS status;
445         struct ldb_result *res = NULL;
446         int ret;
447         struct winsdb_record *rec;
448         struct ldb_context *wins_db = h->ldb;
449         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
450
451         /* find the record in the WINS database */
452         ret = ldb_search(wins_db, winsdb_dn(tmp_ctx, name), LDB_SCOPE_BASE, 
453                          NULL, NULL, &res);
454
455         if (ret != LDB_SUCCESS || res->count > 1) {
456                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
457                 goto failed;
458         } else if (res->count== 0) {
459                 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
460                 goto failed;
461         }
462
463         talloc_steal(tmp_ctx, res);
464
465         status = winsdb_record(h, res->msgs[0], tmp_ctx, &rec);
466         if (!NT_STATUS_IS_OK(status)) goto failed;
467
468         /* see if it has already expired */
469         if (rec->state == WREPL_STATE_ACTIVE &&
470             rec->expire_time <= time(NULL)) {
471                 DEBUG(5,("WINS: expiring name %s (expired at %s)\n", 
472                          nbt_name_string(tmp_ctx, rec->name), timestring(tmp_ctx, rec->expire_time)));
473                 rec->state = WREPL_STATE_RELEASED;
474         }
475
476         talloc_steal(mem_ctx, rec);
477         talloc_free(tmp_ctx);
478         *_rec = rec;
479         return NT_STATUS_OK;
480
481 failed:
482         talloc_free(tmp_ctx);
483         return status;
484 }
485
486 NTSTATUS winsdb_record(struct winsdb_handle *h, struct ldb_message *msg, TALLOC_CTX *mem_ctx, struct winsdb_record **_rec)
487 {
488         NTSTATUS status;
489         struct winsdb_record *rec;
490         struct ldb_message_element *el;
491         struct nbt_name *name;
492         uint32_t i, num_values;
493
494         rec = talloc(mem_ctx, struct winsdb_record);
495         if (rec == NULL) {
496                 status = NT_STATUS_NO_MEMORY;
497                 goto failed;
498         }
499
500         status = winsdb_nbt_name(rec, msg->dn, &name);
501         if (!NT_STATUS_IS_OK(status)) goto failed;
502
503         if (strlen(name->name) > 15) {
504                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
505                 goto failed;
506         }
507         if (name->scope && strlen(name->scope) > 238) {
508                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
509                 goto failed;
510         }
511
512         /* parse it into a more convenient winsdb_record structure */
513         rec->name               = name;
514         rec->type               = ldb_msg_find_int(msg, "recordType", WREPL_TYPE_UNIQUE);
515         rec->state              = ldb_msg_find_int(msg, "recordState", WREPL_STATE_RELEASED);
516         rec->node               = ldb_msg_find_int(msg, "nodeType", WREPL_NODE_B);
517         rec->is_static          = ldb_msg_find_int(msg, "isStatic", 0);
518         rec->expire_time        = ldb_string_to_time(ldb_msg_find_string(msg, "expireTime", NULL));
519         rec->version            = ldb_msg_find_uint64(msg, "versionID", 0);
520         rec->wins_owner         = ldb_msg_find_string(msg, "winsOwner", NULL);
521         rec->registered_by      = ldb_msg_find_string(msg, "registeredBy", NULL);
522         talloc_steal(rec, rec->wins_owner);
523         talloc_steal(rec, rec->registered_by);
524
525         if (!rec->wins_owner || strcmp(rec->wins_owner, "0.0.0.0") == 0) {
526                 rec->wins_owner = h->local_owner;
527         }
528
529         el = ldb_msg_find_element(msg, "address");
530         if (el) {
531                 num_values = el->num_values;
532         } else {
533                 num_values = 0;
534         }
535
536         if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_GROUP) {
537                 if (num_values != 1) {
538                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
539                         goto failed;
540                 }
541         }
542         if (rec->state == WREPL_STATE_ACTIVE) {
543                 if (num_values < 1) {
544                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
545                         goto failed;
546                 }
547         }
548         if (num_values > 25) {
549                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
550                 goto failed;
551         }
552
553         rec->addresses     = talloc_array(rec, struct winsdb_addr *, num_values+1);
554         if (rec->addresses == NULL) {
555                 status = NT_STATUS_NO_MEMORY;
556                 goto failed;
557         }
558
559         for (i=0;i<num_values;i++) {
560                 status = winsdb_addr_decode(h, rec, &el->values[i], rec->addresses, &rec->addresses[i]);
561                 if (!NT_STATUS_IS_OK(status)) goto failed;
562         }
563         rec->addresses[i] = NULL;
564
565         if (rec->is_static) {
566                 if (num_values < 1) {
567                         status = NT_STATUS_INTERNAL_DB_CORRUPTION;
568                         goto failed;
569                 }
570                 rec->state = WREPL_STATE_ACTIVE;
571                 rec->expire_time = get_time_t_max();
572                 for (i=0;rec->addresses[i];i++) {
573                         rec->addresses[i]->expire_time = rec->expire_time;
574                 }
575         }
576
577         *_rec = rec;
578         return NT_STATUS_OK;
579 failed:
580         if (NT_STATUS_EQUAL(NT_STATUS_INTERNAL_DB_CORRUPTION, status)) {
581                 DEBUG(1,("winsdb_record: corrupted record: %s\n", ldb_dn_linearize(rec, msg->dn)));
582         }
583         talloc_free(rec);
584         return status;
585 }
586
587 /*
588   form a ldb_message from a winsdb_record
589 */
590 struct ldb_message *winsdb_message(struct ldb_context *ldb, 
591                                    struct winsdb_record *rec, TALLOC_CTX *mem_ctx)
592 {
593         int i, ret=0;
594         size_t addr_count;
595         const char *expire_time;
596         struct ldb_message *msg = ldb_msg_new(mem_ctx);
597         if (msg == NULL) goto failed;   
598
599         if (rec->is_static) {
600                 rec->state = WREPL_STATE_ACTIVE;
601                 rec->expire_time = get_time_t_max();
602                 for (i=0;rec->addresses[i];i++) {
603                         rec->addresses[i]->expire_time = rec->expire_time;
604                 }
605         }
606
607         /* make sure we don't put in corrupted records */
608         addr_count = winsdb_addr_list_length(rec->addresses);
609         if (rec->state == WREPL_STATE_ACTIVE && addr_count == 0) {
610                 rec->state = WREPL_STATE_RELEASED;
611         }
612         if (rec->type == WREPL_TYPE_UNIQUE && addr_count > 1) {
613                 rec->type = WREPL_TYPE_MHOMED;
614         }
615
616         expire_time = ldb_timestring(msg, rec->expire_time);
617         if (!expire_time) {
618                 goto failed;
619         }
620
621         msg->dn = winsdb_dn(msg, rec->name);
622         if (msg->dn == NULL) goto failed;
623         ret |= ldb_msg_add_fmt(msg, "type", "0x%02X", rec->name->type);
624         if (rec->name->name && *rec->name->name) {
625                 ret |= ldb_msg_add_string(msg, "name", rec->name->name);
626         }
627         if (rec->name->scope && *rec->name->scope) {
628                 ret |= ldb_msg_add_string(msg, "scope", rec->name->scope);
629         }
630         ret |= ldb_msg_add_fmt(msg, "objectClass", "winsRecord");
631         ret |= ldb_msg_add_fmt(msg, "recordType", "%u", rec->type);
632         ret |= ldb_msg_add_fmt(msg, "recordState", "%u", rec->state);
633         ret |= ldb_msg_add_fmt(msg, "nodeType", "%u", rec->node);
634         ret |= ldb_msg_add_fmt(msg, "isStatic", "%u", rec->is_static);
635         ret |= ldb_msg_add_string(msg, "expireTime", expire_time);
636         ret |= ldb_msg_add_fmt(msg, "versionID", "%llu", (long long)rec->version);
637         ret |= ldb_msg_add_string(msg, "winsOwner", rec->wins_owner);
638         ret |= ldb_msg_add_empty(msg, "address", 0);
639         for (i=0;rec->addresses[i];i++) {
640                 ret |= ldb_msg_add_winsdb_addr(msg, "address", rec->addresses[i]);
641         }
642         ret |= ldb_msg_add_empty(msg, "registeredBy", 0);
643         if (rec->registered_by) {
644                 ret |= ldb_msg_add_string(msg, "registeredBy", rec->registered_by);
645                 if (ret != 0) goto failed;
646         }
647         return msg;
648
649 failed:
650         talloc_free(msg);
651         return NULL;
652 }
653
654 /*
655   save a WINS record into the database
656 */
657 uint8_t winsdb_add(struct winsdb_handle *h, struct winsdb_record *rec, uint32_t flags)
658 {
659         struct ldb_message *msg;
660         struct ldb_context *wins_db = h->ldb;
661         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
662         int trans = -1;
663         int ret = 0;
664
665         trans = ldb_transaction_start(wins_db);
666         if (trans != LDB_SUCCESS) goto failed;
667
668         if (flags & WINSDB_FLAG_ALLOC_VERSION) {
669                 /* passing '0' means auto-allocate a new one */
670                 rec->version = winsdb_set_maxVersion(h, 0);
671                 if (rec->version == 0) goto failed;
672         }
673         if (flags & WINSDB_FLAG_TAKE_OWNERSHIP) {
674                 rec->wins_owner = h->local_owner;
675         }
676
677         msg = winsdb_message(wins_db, rec, tmp_ctx);
678         if (msg == NULL) goto failed;
679         ret = ldb_add(wins_db, msg);
680         if (ret != 0) goto failed;
681
682         trans = ldb_transaction_commit(wins_db);
683         if (trans != LDB_SUCCESS) goto failed;
684
685         talloc_free(tmp_ctx);
686         return NBT_RCODE_OK;
687
688 failed:
689         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
690         talloc_free(tmp_ctx);
691         return NBT_RCODE_SVR;
692 }
693
694
695 /*
696   modify a WINS record in the database
697 */
698 uint8_t winsdb_modify(struct winsdb_handle *h, struct winsdb_record *rec, uint32_t flags)
699 {
700         struct ldb_message *msg;
701         struct ldb_context *wins_db = h->ldb;
702         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
703         int trans;
704         int ret;
705         int i;
706
707         trans = ldb_transaction_start(wins_db);
708         if (trans != LDB_SUCCESS) goto failed;
709
710         if (flags & WINSDB_FLAG_ALLOC_VERSION) {
711                 /* passing '0' means auto-allocate a new one */
712                 rec->version = winsdb_set_maxVersion(h, 0);
713                 if (rec->version == 0) goto failed;
714         }
715         if (flags & WINSDB_FLAG_TAKE_OWNERSHIP) {
716                 rec->wins_owner = h->local_owner;
717         }
718
719         msg = winsdb_message(wins_db, rec, tmp_ctx);
720         if (msg == NULL) goto failed;
721
722         for (i=0;i<msg->num_elements;i++) {
723                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
724         }
725
726         ret = ldb_modify(wins_db, msg);
727         if (ret != 0) goto failed;
728
729         trans = ldb_transaction_commit(wins_db);
730         if (trans != LDB_SUCCESS) goto failed;
731
732         talloc_free(tmp_ctx);
733         return NBT_RCODE_OK;
734
735 failed:
736         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
737         talloc_free(tmp_ctx);
738         return NBT_RCODE_SVR;
739 }
740
741
742 /*
743   delete a WINS record from the database
744 */
745 uint8_t winsdb_delete(struct winsdb_handle *h, struct winsdb_record *rec)
746 {
747         struct ldb_context *wins_db = h->ldb;
748         TALLOC_CTX *tmp_ctx = talloc_new(wins_db);
749         const struct ldb_dn *dn;
750         int trans;
751         int ret;
752
753         trans = ldb_transaction_start(wins_db);
754         if (trans != LDB_SUCCESS) goto failed;
755
756         dn = winsdb_dn(tmp_ctx, rec->name);
757         if (dn == NULL) goto failed;
758
759         ret = ldb_delete(wins_db, dn);
760         if (ret != 0) goto failed;
761
762         trans = ldb_transaction_commit(wins_db);
763         if (trans != LDB_SUCCESS) goto failed;
764
765         talloc_free(tmp_ctx);
766         return NBT_RCODE_OK;
767
768 failed:
769         if (trans == LDB_SUCCESS) ldb_transaction_cancel(wins_db);
770         talloc_free(tmp_ctx);
771         return NBT_RCODE_SVR;
772 }
773
774 struct winsdb_handle *winsdb_connect(TALLOC_CTX *mem_ctx)
775 {
776         struct winsdb_handle *h = NULL;
777         const char *owner;
778
779         h = talloc(mem_ctx, struct winsdb_handle);
780         if (!h) return NULL;
781
782         h->ldb = ldb_wrap_connect(h, lock_path(h, lp_wins_url()),
783                                   system_session(h), NULL, 0, NULL);
784         if (!h->ldb) goto failed;
785
786         owner = lp_parm_string(-1, "winsdb", "local_owner");
787         if (!owner) {
788                 owner = iface_n_ip(0);
789         }
790
791         h->local_owner = talloc_strdup(h, owner);
792         if (!h->local_owner) goto failed;
793
794         return h;
795 failed:
796         talloc_free(h);
797         return NULL;
798 }