2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005
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 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/wins/winsdb.h"
27 #include <ldb_errors.h>
28 #include "librpc/gen_ndr/ndr_nbt.h"
29 #include "system/time.h"
31 #include "system/network.h"
32 #include "lib/socket/netif.h"
33 #include "param/param.h"
34 #include "lib/util/smb_strtox.h"
35 #include "lib/util/tsort.h"
39 uint64_t winsdb_get_maxVersion(struct winsdb_handle
*h
)
42 struct ldb_context
*ldb
= h
->ldb
;
44 struct ldb_result
*res
= NULL
;
45 TALLOC_CTX
*tmp_ctx
= talloc_new(ldb
);
46 uint64_t maxVersion
= 0;
48 dn
= ldb_dn_new(tmp_ctx
, ldb
, "CN=VERSION");
51 /* find the record in the WINS database */
52 ret
= ldb_search(ldb
, tmp_ctx
, &res
, dn
, LDB_SCOPE_BASE
, NULL
, NULL
);
53 if (ret
!= LDB_SUCCESS
) goto failed
;
54 if (res
->count
> 1) goto failed
;
56 if (res
->count
== 1) {
57 maxVersion
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "maxVersion", 0);
66 if newVersion == 0 return the old maxVersion + 1 and save it
67 if newVersion > 0 return MAX(oldMaxVersion, newMaxVersion) and save it
69 uint64_t winsdb_set_maxVersion(struct winsdb_handle
*h
, uint64_t newMaxVersion
)
74 struct ldb_result
*res
= NULL
;
75 struct ldb_message
*msg
= NULL
;
76 struct ldb_context
*wins_db
= h
->ldb
;
77 TALLOC_CTX
*tmp_ctx
= talloc_new(wins_db
);
78 uint64_t oldMaxVersion
= 0;
80 trans
= ldb_transaction_start(wins_db
);
81 if (trans
!= LDB_SUCCESS
) goto failed
;
83 dn
= ldb_dn_new(tmp_ctx
, wins_db
, "CN=VERSION");
86 /* find the record in the WINS database */
87 ret
= ldb_search(wins_db
, tmp_ctx
, &res
, dn
, LDB_SCOPE_BASE
, NULL
, NULL
);
88 if (ret
!= LDB_SUCCESS
) goto failed
;
89 if (res
->count
> 1) goto failed
;
91 if (res
->count
== 1) {
92 oldMaxVersion
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "maxVersion", 0);
95 if (newMaxVersion
== 0) {
96 newMaxVersion
= oldMaxVersion
+ 1;
98 newMaxVersion
= MAX(oldMaxVersion
, newMaxVersion
);
101 msg
= ldb_msg_new(tmp_ctx
);
102 if (!msg
) goto failed
;
106 ret
= ldb_msg_append_string(msg
, "objectClass", "winsMaxVersion",
107 LDB_FLAG_MOD_REPLACE
);
108 if (ret
!= LDB_SUCCESS
) goto failed
;
109 ret
= ldb_msg_append_fmt(msg
, LDB_FLAG_MOD_REPLACE
,
110 "maxVersion", "%llu", (long long)newMaxVersion
);
111 if (ret
!= LDB_SUCCESS
) goto failed
;
113 ret
= ldb_modify(wins_db
, msg
);
114 if (ret
!= LDB_SUCCESS
) ret
= ldb_add(wins_db
, msg
);
115 if (ret
!= LDB_SUCCESS
) goto failed
;
117 trans
= ldb_transaction_commit(wins_db
);
118 if (trans
!= LDB_SUCCESS
) goto failed
;
120 talloc_free(tmp_ctx
);
121 return newMaxVersion
;
124 if (trans
== LDB_SUCCESS
) ldb_transaction_cancel(wins_db
);
125 talloc_free(tmp_ctx
);
130 return a DN for a nbt_name
132 static struct ldb_dn
*winsdb_dn(TALLOC_CTX
*mem_ctx
, struct ldb_context
*ldb
,
133 const struct nbt_name
*name
)
137 dn
= ldb_dn_new_fmt(mem_ctx
, ldb
, "type=0x%02X", name
->type
);
138 if (ldb_dn_is_valid(dn
) && name
->name
&& *name
->name
) {
139 ldb_dn_add_child_fmt(dn
, "name=%s", name
->name
);
141 if (ldb_dn_is_valid(dn
) && name
->scope
&& *name
->scope
) {
142 ldb_dn_add_child_fmt(dn
, "scope=%s", name
->scope
);
147 static NTSTATUS
winsdb_nbt_name(TALLOC_CTX
*mem_ctx
, struct ldb_dn
*dn
, struct nbt_name
**_name
)
150 struct nbt_name
*name
;
151 unsigned int comp_num
;
155 name
= talloc(mem_ctx
, struct nbt_name
);
157 status
= NT_STATUS_NO_MEMORY
;
161 comp_num
= ldb_dn_get_comp_num(dn
);
164 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
168 if (comp_num
> cur
&& strcasecmp("scope", ldb_dn_get_component_name(dn
, cur
)) == 0) {
169 name
->scope
= (const char *)talloc_strdup(name
, (char *)ldb_dn_get_component_val(dn
, cur
)->data
);
175 if (comp_num
> cur
&& strcasecmp("name", ldb_dn_get_component_name(dn
, cur
)) == 0) {
176 name
->name
= (const char *)talloc_strdup(name
, (char *)ldb_dn_get_component_val(dn
, cur
)->data
);
179 name
->name
= talloc_strdup(name
, "");
181 status
= NT_STATUS_NO_MEMORY
;
186 if (comp_num
> cur
&& strcasecmp("type", ldb_dn_get_component_name(dn
, cur
)) == 0) {
189 (char *)ldb_dn_get_component_val(dn
, cur
)->data
,
195 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
200 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
212 decode the winsdb_addr("address") attribute:
214 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
217 static NTSTATUS
winsdb_addr_decode(struct winsdb_handle
*h
, struct winsdb_record
*rec
, struct ldb_val
*val
,
218 TALLOC_CTX
*mem_ctx
, struct winsdb_addr
**_addr
)
221 struct winsdb_addr
*addr
;
223 const char *wins_owner
;
224 const char *expire_time
;
227 addr
= talloc(mem_ctx
, struct winsdb_addr
);
229 status
= NT_STATUS_NO_MEMORY
;
233 address
= (char *)val
->data
;
235 p
= strchr(address
, ';');
237 /* support old entries, with only the address */
238 addr
->address
= (const char *)talloc_steal(addr
, val
->data
);
239 addr
->wins_owner
= talloc_strdup(addr
, rec
->wins_owner
);
240 if (!addr
->wins_owner
) {
241 status
= NT_STATUS_NO_MEMORY
;
244 addr
->expire_time
= rec
->expire_time
;
250 addr
->address
= talloc_strdup(addr
, address
);
251 if (!addr
->address
) {
252 status
= NT_STATUS_NO_MEMORY
;
256 if (strncmp("winsOwner:", p
, 10) != 0) {
257 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
261 p
= strchr(wins_owner
, ';');
263 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
268 if (strcmp(wins_owner
, "0.0.0.0") == 0) {
269 wins_owner
= h
->local_owner
;
271 addr
->wins_owner
= talloc_strdup(addr
, wins_owner
);
272 if (!addr
->wins_owner
) {
273 status
= NT_STATUS_NO_MEMORY
;
277 if (strncmp("expireTime:", p
, 11) != 0) {
278 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
282 expire_time
= p
+ 11;
283 p
= strchr(expire_time
, ';');
285 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
290 addr
->expire_time
= ldb_string_to_time(expire_time
);
300 encode the winsdb_addr("address") attribute like this:
302 "172.31.1.1;winsOwner:172.31.9.202;expireTime:20050923032330.0Z;"
306 static int ldb_msg_add_winsdb_addr(struct ldb_message
*msg
, struct winsdb_record
*rec
,
307 const char *attr_name
, struct winsdb_addr
*addr
)
311 if (rec
->is_static
) {
312 str
= talloc_strdup(msg
, addr
->address
);
313 if (!str
) return LDB_ERR_OPERATIONS_ERROR
;
316 expire_time
= ldb_timestring(msg
, addr
->expire_time
);
317 if (!expire_time
) return LDB_ERR_OPERATIONS_ERROR
;
318 str
= talloc_asprintf(msg
, "%s;winsOwner:%s;expireTime:%s;",
319 addr
->address
, addr
->wins_owner
,
321 talloc_free(expire_time
);
322 if (!str
) return LDB_ERR_OPERATIONS_ERROR
;
325 return ldb_msg_add_string(msg
, attr_name
, str
);
328 struct winsdb_addr
**winsdb_addr_list_make(TALLOC_CTX
*mem_ctx
)
330 struct winsdb_addr
**addresses
;
332 addresses
= talloc_array(mem_ctx
, struct winsdb_addr
*, 1);
333 if (!addresses
) return NULL
;
340 static int winsdb_addr_sort_list (struct winsdb_addr
**p1
, struct winsdb_addr
**p2
, void *opaque
)
342 struct winsdb_addr
*a1
= talloc_get_type(*p1
, struct winsdb_addr
);
343 struct winsdb_addr
*a2
= talloc_get_type(*p2
, struct winsdb_addr
);
344 struct winsdb_handle
*h
= talloc_get_type(opaque
, struct winsdb_handle
);
345 bool a1_owned
= false;
346 bool a2_owned
= false;
349 * first the owned addresses with the newest to the oldest address
350 * then the replica addresses with the newest to the oldest address
352 if (a2
->expire_time
!= a1
->expire_time
) {
353 return NUMERIC_CMP(a2
->expire_time
, a1
->expire_time
);
356 if (strcmp(a2
->wins_owner
, h
->local_owner
) == 0) {
360 if (strcmp(a1
->wins_owner
, h
->local_owner
) == 0) {
364 return NUMERIC_CMP(a2_owned
, a1_owned
);
367 struct winsdb_addr
**winsdb_addr_list_add(struct winsdb_handle
*h
, const struct winsdb_record
*rec
,
368 struct winsdb_addr
**addresses
, const char *address
,
369 const char *wins_owner
, time_t expire_time
,
370 bool is_name_registration
)
372 struct winsdb_addr
*old_addr
= NULL
;
375 bool found_old_replica
= false;
378 * count the addresses and maybe
379 * find an old entry for the new address
381 for (i
=0; addresses
[i
]; i
++) {
382 if (old_addr
) continue;
383 if (strcmp(addresses
[i
]->address
, address
) == 0) {
384 old_addr
= addresses
[i
];
390 * the address is already there
391 * and we can replace it
394 goto remove_old_addr
;
398 * if we don't have 25 addresses already,
399 * we can just add the new address
406 * if we haven't found the address,
407 * and we have already have 25 addresses
408 * if so then we need to do the following:
409 * - if it isn't a name registration, then just ignore the new address
410 * - if it is a name registration, then first search for
411 * the oldest replica and if there's no replica address
412 * search the oldest owned address
414 if (!is_name_registration
) {
419 * find the oldest replica address, if there's no replica
420 * record at all, find the oldest owned address
422 for (i
=0; addresses
[i
]; i
++) {
423 bool cur_is_replica
= false;
424 /* find out if the current address is a replica */
425 if (strcmp(addresses
[i
]->wins_owner
, h
->local_owner
) != 0) {
426 cur_is_replica
= true;
430 * if we already found a replica address and the current address
431 * is not a replica, then skip it
433 if (found_old_replica
&& !cur_is_replica
) continue;
436 * if we found the first replica address, reset the address
437 * that would be replaced
439 if (!found_old_replica
&& cur_is_replica
) {
440 found_old_replica
= true;
441 old_addr
= addresses
[i
];
446 * if the first address isn't a replica, just start with
450 old_addr
= addresses
[i
];
455 * see if we find an older address
457 if (addresses
[i
]->expire_time
< old_addr
->expire_time
) {
458 old_addr
= addresses
[i
];
464 winsdb_addr_list_remove(addresses
, old_addr
->address
);
468 addresses
= talloc_realloc(addresses
, addresses
, struct winsdb_addr
*, len
+ 2);
469 if (!addresses
) return NULL
;
471 addresses
[len
] = talloc(addresses
, struct winsdb_addr
);
472 if (!addresses
[len
]) {
473 talloc_free(addresses
);
477 addresses
[len
]->address
= talloc_strdup(addresses
[len
], address
);
478 if (!addresses
[len
]->address
) {
479 talloc_free(addresses
);
483 addresses
[len
]->wins_owner
= talloc_strdup(addresses
[len
], wins_owner
);
484 if (!addresses
[len
]->wins_owner
) {
485 talloc_free(addresses
);
489 addresses
[len
]->expire_time
= expire_time
;
491 addresses
[len
+1] = NULL
;
493 LDB_TYPESAFE_QSORT(addresses
, len
+1, h
, winsdb_addr_sort_list
);
498 void winsdb_addr_list_remove(struct winsdb_addr
**addresses
, const char *address
)
502 for (i
=0; addresses
[i
]; i
++) {
503 if (strcmp(addresses
[i
]->address
, address
) == 0) {
508 for (; addresses
[i
]; i
++) {
509 addresses
[i
] = addresses
[i
+1];
515 struct winsdb_addr
*winsdb_addr_list_check(struct winsdb_addr
**addresses
, const char *address
)
519 for (i
=0; addresses
[i
]; i
++) {
520 if (strcmp(addresses
[i
]->address
, address
) == 0) {
528 size_t winsdb_addr_list_length(struct winsdb_addr
**addresses
)
531 for (i
=0; addresses
[i
]; i
++);
535 const char **winsdb_addr_string_list(TALLOC_CTX
*mem_ctx
, struct winsdb_addr
**addresses
)
537 size_t len
= winsdb_addr_list_length(addresses
);
538 const char **str_list
=NULL
;
541 for (i
=0; i
< len
; i
++) {
542 str_list
= str_list_add(str_list
, addresses
[i
]->address
);
547 talloc_steal(mem_ctx
, str_list
);
552 load a WINS entry from the database
554 NTSTATUS
winsdb_lookup(struct winsdb_handle
*h
,
555 const struct nbt_name
*name
,
557 struct winsdb_record
**_rec
)
560 struct ldb_result
*res
= NULL
;
562 struct winsdb_record
*rec
;
563 struct ldb_context
*wins_db
= h
->ldb
;
564 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
565 time_t now
= time(NULL
);
567 /* find the record in the WINS database */
568 ret
= ldb_search(wins_db
, tmp_ctx
, &res
,
569 winsdb_dn(tmp_ctx
, wins_db
, name
),
570 LDB_SCOPE_BASE
, NULL
, NULL
);
572 if (ret
!= LDB_SUCCESS
|| res
->count
> 1) {
573 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
575 } else if (res
->count
== 0) {
576 status
= NT_STATUS_OBJECT_NAME_NOT_FOUND
;
580 status
= winsdb_record(h
, res
->msgs
[0], tmp_ctx
, now
, &rec
);
581 if (!NT_STATUS_IS_OK(status
)) goto failed
;
583 talloc_steal(mem_ctx
, rec
);
584 talloc_free(tmp_ctx
);
589 talloc_free(tmp_ctx
);
593 NTSTATUS
winsdb_record(struct winsdb_handle
*h
, struct ldb_message
*msg
, TALLOC_CTX
*mem_ctx
, time_t now
, struct winsdb_record
**_rec
)
596 struct winsdb_record
*rec
;
597 struct ldb_message_element
*el
;
598 struct nbt_name
*name
;
599 uint32_t i
, j
, num_values
;
601 rec
= talloc(mem_ctx
, struct winsdb_record
);
603 status
= NT_STATUS_NO_MEMORY
;
607 status
= winsdb_nbt_name(rec
, msg
->dn
, &name
);
608 if (!NT_STATUS_IS_OK(status
)) goto failed
;
610 if (strlen(name
->name
) > 15) {
611 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
614 if (name
->scope
&& strlen(name
->scope
) > 238) {
615 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
619 /* parse it into a more convenient winsdb_record structure */
621 rec
->type
= ldb_msg_find_attr_as_int(msg
, "recordType", WREPL_TYPE_UNIQUE
);
622 rec
->state
= ldb_msg_find_attr_as_int(msg
, "recordState", WREPL_STATE_RELEASED
);
623 rec
->node
= ldb_msg_find_attr_as_int(msg
, "nodeType", WREPL_NODE_B
);
624 rec
->is_static
= ldb_msg_find_attr_as_int(msg
, "isStatic", 0);
625 rec
->expire_time
= ldb_string_to_time(ldb_msg_find_attr_as_string(msg
, "expireTime", NULL
));
626 rec
->version
= ldb_msg_find_attr_as_uint64(msg
, "versionID", 0);
627 rec
->wins_owner
= ldb_msg_find_attr_as_string(msg
, "winsOwner", NULL
);
628 rec
->registered_by
= ldb_msg_find_attr_as_string(msg
, "registeredBy", NULL
);
629 talloc_steal(rec
, rec
->wins_owner
);
630 talloc_steal(rec
, rec
->registered_by
);
632 if (!rec
->wins_owner
|| strcmp(rec
->wins_owner
, "0.0.0.0") == 0) {
633 rec
->wins_owner
= h
->local_owner
;
636 el
= ldb_msg_find_element(msg
, "address");
638 num_values
= el
->num_values
;
643 if (rec
->type
== WREPL_TYPE_UNIQUE
|| rec
->type
== WREPL_TYPE_GROUP
) {
644 if (num_values
!= 1) {
645 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
649 if (rec
->state
== WREPL_STATE_ACTIVE
) {
650 if (num_values
< 1) {
651 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
655 if (num_values
> 25) {
656 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
660 rec
->addresses
= talloc_array(rec
, struct winsdb_addr
*, num_values
+1);
661 if (rec
->addresses
== NULL
) {
662 status
= NT_STATUS_NO_MEMORY
;
666 for (i
=0,j
=0;i
<num_values
;i
++) {
667 bool we_are_owner
= false;
669 status
= winsdb_addr_decode(h
, rec
, &el
->values
[i
], rec
->addresses
, &rec
->addresses
[j
]);
670 if (!NT_STATUS_IS_OK(status
)) goto failed
;
672 if (strcmp(rec
->addresses
[j
]->wins_owner
, h
->local_owner
) == 0) {
677 * the record isn't static and is active
678 * then don't add the address if it's expired,
679 * but only if we're the owner of the address
681 * This is important for SGROUP records,
682 * because each server thinks he's the owner of the
683 * record and the record isn't replicated on a
684 * name_refresh. So addresses owned by another owner
685 * could expire, but we still need to return them
688 if (!rec
->is_static
&&
689 rec
->addresses
[j
]->expire_time
<= now
&&
690 rec
->state
== WREPL_STATE_ACTIVE
&&
692 DEBUG(5,("WINS: expiring name addr %s of %s (expired at %s)\n",
693 rec
->addresses
[j
]->address
, nbt_name_string(rec
->addresses
[j
], rec
->name
),
694 timestring(rec
->addresses
[j
], rec
->addresses
[j
]->expire_time
)));
695 talloc_free(rec
->addresses
[j
]);
696 rec
->addresses
[j
] = NULL
;
701 rec
->addresses
[j
] = NULL
;
704 if (rec
->is_static
&& rec
->state
== WREPL_STATE_ACTIVE
) {
705 rec
->expire_time
= get_time_t_max();
706 for (i
=0;rec
->addresses
[i
];i
++) {
707 rec
->addresses
[i
]->expire_time
= rec
->expire_time
;
711 if (rec
->state
== WREPL_STATE_ACTIVE
) {
712 if (num_values
< 1) {
713 DEBUG(5,("WINS: expiring name %s (because it has no active addresses)\n",
714 nbt_name_string(mem_ctx
, rec
->name
)));
715 rec
->state
= WREPL_STATE_RELEASED
;
722 if (NT_STATUS_EQUAL(NT_STATUS_INTERNAL_DB_CORRUPTION
, status
)) {
723 DEBUG(1,("winsdb_record: corrupted record: %s\n", ldb_dn_get_linearized(msg
->dn
)));
730 form a ldb_message from a winsdb_record
732 static struct ldb_message
*winsdb_message(struct ldb_context
*ldb
,
733 struct winsdb_record
*rec
,
738 const char *expire_time
;
739 struct ldb_message
*msg
= ldb_msg_new(mem_ctx
);
740 if (msg
== NULL
) goto failed
;
742 /* make sure we don't put in corrupted records */
743 addr_count
= winsdb_addr_list_length(rec
->addresses
);
744 if (rec
->state
== WREPL_STATE_ACTIVE
&& addr_count
== 0) {
745 rec
->state
= WREPL_STATE_RELEASED
;
747 if (rec
->type
== WREPL_TYPE_UNIQUE
&& addr_count
> 1) {
748 rec
->type
= WREPL_TYPE_MHOMED
;
751 expire_time
= ldb_timestring(msg
, rec
->expire_time
);
756 msg
->dn
= winsdb_dn(msg
, ldb
, rec
->name
);
757 if (msg
->dn
== NULL
) goto failed
;
758 ret
= ldb_msg_add_fmt(msg
, "type", "0x%02X", rec
->name
->type
);
759 if (rec
->name
->name
&& *rec
->name
->name
) {
760 ret
|= ldb_msg_add_string(msg
, "name", rec
->name
->name
);
762 if (rec
->name
->scope
&& *rec
->name
->scope
) {
763 ret
|= ldb_msg_add_string(msg
, "scope", rec
->name
->scope
);
765 ret
|= ldb_msg_add_fmt(msg
, "objectClass", "winsRecord");
766 ret
|= ldb_msg_add_fmt(msg
, "recordType", "%u", rec
->type
);
767 ret
|= ldb_msg_add_fmt(msg
, "recordState", "%u", rec
->state
);
768 ret
|= ldb_msg_add_fmt(msg
, "nodeType", "%u", rec
->node
);
769 ret
|= ldb_msg_add_fmt(msg
, "isStatic", "%u", rec
->is_static
);
770 ret
|= ldb_msg_add_empty(msg
, "expireTime", 0, NULL
);
771 if (!(rec
->is_static
&& rec
->state
== WREPL_STATE_ACTIVE
)) {
772 ret
|= ldb_msg_add_string(msg
, "expireTime", expire_time
);
774 ret
|= ldb_msg_add_fmt(msg
, "versionID", "%llu", (long long)rec
->version
);
775 ret
|= ldb_msg_add_string(msg
, "winsOwner", rec
->wins_owner
);
776 ret
|= ldb_msg_add_empty(msg
, "address", 0, NULL
);
777 for (i
=0;rec
->addresses
[i
];i
++) {
778 ret
|= ldb_msg_add_winsdb_addr(msg
, rec
, "address", rec
->addresses
[i
]);
780 if (rec
->registered_by
) {
781 ret
|= ldb_msg_append_string(msg
, "registeredBy", rec
->registered_by
, 0);
783 if (ret
!= LDB_SUCCESS
) goto failed
;
792 save a WINS record into the database
794 uint8_t winsdb_add(struct winsdb_handle
*h
, struct winsdb_record
*rec
, uint32_t flags
)
796 struct ldb_message
*msg
;
797 struct ldb_context
*wins_db
= h
->ldb
;
798 TALLOC_CTX
*tmp_ctx
= talloc_new(wins_db
);
802 trans
= ldb_transaction_start(wins_db
);
803 if (trans
!= LDB_SUCCESS
) goto failed
;
805 if (flags
& WINSDB_FLAG_ALLOC_VERSION
) {
806 /* passing '0' means auto-allocate a new one */
807 rec
->version
= winsdb_set_maxVersion(h
, 0);
808 if (rec
->version
== 0) goto failed
;
810 if (flags
& WINSDB_FLAG_TAKE_OWNERSHIP
) {
811 rec
->wins_owner
= h
->local_owner
;
814 msg
= winsdb_message(wins_db
, rec
, tmp_ctx
);
815 if (msg
== NULL
) goto failed
;
816 ret
= ldb_add(wins_db
, msg
);
817 if (ret
!= LDB_SUCCESS
) goto failed
;
819 trans
= ldb_transaction_commit(wins_db
);
820 if (trans
!= LDB_SUCCESS
) goto failed
;
822 wins_hook(h
, rec
, WINS_HOOK_ADD
, h
->hook_script
);
824 talloc_free(tmp_ctx
);
828 if (trans
== LDB_SUCCESS
) ldb_transaction_cancel(wins_db
);
829 talloc_free(tmp_ctx
);
830 return NBT_RCODE_SVR
;
835 modify a WINS record in the database
837 uint8_t winsdb_modify(struct winsdb_handle
*h
, struct winsdb_record
*rec
, uint32_t flags
)
839 struct ldb_message
*msg
;
840 struct ldb_context
*wins_db
= h
->ldb
;
841 TALLOC_CTX
*tmp_ctx
= talloc_new(wins_db
);
846 trans
= ldb_transaction_start(wins_db
);
847 if (trans
!= LDB_SUCCESS
) goto failed
;
849 if (flags
& WINSDB_FLAG_ALLOC_VERSION
) {
850 /* passing '0' means auto-allocate a new one */
851 rec
->version
= winsdb_set_maxVersion(h
, 0);
852 if (rec
->version
== 0) goto failed
;
854 if (flags
& WINSDB_FLAG_TAKE_OWNERSHIP
) {
855 rec
->wins_owner
= h
->local_owner
;
858 msg
= winsdb_message(wins_db
, rec
, tmp_ctx
);
859 if (msg
== NULL
) goto failed
;
861 for (i
=0;i
<msg
->num_elements
;i
++) {
862 msg
->elements
[i
].flags
= LDB_FLAG_MOD_REPLACE
;
865 ret
= ldb_modify(wins_db
, msg
);
866 if (ret
!= LDB_SUCCESS
) goto failed
;
868 trans
= ldb_transaction_commit(wins_db
);
869 if (trans
!= LDB_SUCCESS
) goto failed
;
871 wins_hook(h
, rec
, WINS_HOOK_MODIFY
, h
->hook_script
);
873 talloc_free(tmp_ctx
);
877 if (trans
== LDB_SUCCESS
) ldb_transaction_cancel(wins_db
);
878 talloc_free(tmp_ctx
);
879 return NBT_RCODE_SVR
;
884 delete a WINS record from the database
886 uint8_t winsdb_delete(struct winsdb_handle
*h
, struct winsdb_record
*rec
)
888 struct ldb_context
*wins_db
= h
->ldb
;
889 TALLOC_CTX
*tmp_ctx
= talloc_new(wins_db
);
894 trans
= ldb_transaction_start(wins_db
);
895 if (trans
!= LDB_SUCCESS
) goto failed
;
897 dn
= winsdb_dn(tmp_ctx
, wins_db
, rec
->name
);
898 if (dn
== NULL
) goto failed
;
900 ret
= ldb_delete(wins_db
, dn
);
901 if (ret
!= LDB_SUCCESS
) goto failed
;
903 trans
= ldb_transaction_commit(wins_db
);
904 if (trans
!= LDB_SUCCESS
) goto failed
;
906 wins_hook(h
, rec
, WINS_HOOK_DELETE
, h
->hook_script
);
908 talloc_free(tmp_ctx
);
912 if (trans
== LDB_SUCCESS
) ldb_transaction_cancel(wins_db
);
913 talloc_free(tmp_ctx
);
914 return NBT_RCODE_SVR
;
917 static bool winsdb_check_or_add_module_list(struct tevent_context
*ev_ctx
,
918 struct loadparm_context
*lp_ctx
, struct winsdb_handle
*h
,
919 const char *wins_path
)
924 struct ldb_result
*res
= NULL
;
925 struct ldb_message
*msg
= NULL
;
926 TALLOC_CTX
*tmp_ctx
= talloc_new(h
);
927 unsigned int flags
= 0;
929 trans
= ldb_transaction_start(h
->ldb
);
930 if (trans
!= LDB_SUCCESS
) goto failed
;
932 /* check if we have a special @MODULES record already */
933 dn
= ldb_dn_new(tmp_ctx
, h
->ldb
, "@MODULES");
934 if (!dn
) goto failed
;
936 /* find the record in the WINS database */
937 ret
= ldb_search(h
->ldb
, tmp_ctx
, &res
, dn
, LDB_SCOPE_BASE
, NULL
, NULL
);
938 if (ret
!= LDB_SUCCESS
) goto failed
;
940 if (res
->count
> 0) goto skip
;
942 /* if there's no record, add one */
943 msg
= ldb_msg_new(tmp_ctx
);
944 if (!msg
) goto failed
;
947 ret
= ldb_msg_add_string(msg
, "@LIST", "wins_ldb");
948 if (ret
!= LDB_SUCCESS
) goto failed
;
950 ret
= ldb_add(h
->ldb
, msg
);
951 if (ret
!= LDB_SUCCESS
) goto failed
;
953 trans
= ldb_transaction_commit(h
->ldb
);
954 if (trans
!= LDB_SUCCESS
) goto failed
;
956 /* close and reopen the database, with the modules */
957 trans
= LDB_ERR_OTHER
;
961 if (lpcfg_parm_bool(lp_ctx
, NULL
,"winsdb", "nosync", false)) {
962 flags
|= LDB_FLG_NOSYNC
;
965 h
->ldb
= ldb_wrap_connect(h
, ev_ctx
, lp_ctx
, wins_path
,
967 if (!h
->ldb
) goto failed
;
969 talloc_free(tmp_ctx
);
973 if (trans
== LDB_SUCCESS
) ldb_transaction_cancel(h
->ldb
);
974 talloc_free(tmp_ctx
);
978 if (trans
== LDB_SUCCESS
) ldb_transaction_cancel(h
->ldb
);
979 talloc_free(tmp_ctx
);
983 struct winsdb_handle
*winsdb_connect(TALLOC_CTX
*mem_ctx
,
984 struct tevent_context
*ev_ctx
,
985 struct loadparm_context
*lp_ctx
,
987 enum winsdb_handle_caller caller
)
989 const struct loadparm_substitution
*lp_sub
=
990 lpcfg_noop_substitution();
991 struct winsdb_handle
*h
= NULL
;
992 unsigned int flags
= 0;
997 h
= talloc_zero(mem_ctx
, struct winsdb_handle
);
1000 wins_path
= lpcfg_state_path(h
, lp_ctx
, "wins.ldb");
1002 if (lpcfg_parm_bool(lp_ctx
, NULL
,"winsdb", "nosync", false)) {
1003 flags
|= LDB_FLG_NOSYNC
;
1006 h
->ldb
= ldb_wrap_connect(h
, ev_ctx
, lp_ctx
, wins_path
,
1008 if (!h
->ldb
) goto failed
;
1011 h
->hook_script
= lpcfg_wins_hook(lp_ctx
, lp_sub
, h
);
1013 h
->local_owner
= talloc_strdup(h
, owner
);
1014 if (!h
->local_owner
) goto failed
;
1016 /* make sure the module list is available and used */
1017 ret
= winsdb_check_or_add_module_list(ev_ctx
, lp_ctx
, h
, wins_path
);
1018 if (!ret
) goto failed
;
1020 ldb_err
= ldb_set_opaque(h
->ldb
, "winsdb_handle", h
);
1021 if (ldb_err
!= LDB_SUCCESS
) goto failed
;