Pass struct smb_request to file_new
[Samba/gebeck_regimport.git] / source4 / nbt_server / wins / winsserver.c
blob399530b4cf75a7eda65b7dc72ef7eab458a88c8b
1 /*
2 Unix SMB/CIFS implementation.
4 core wins server handling
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/>.
23 #include "includes.h"
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/wins/winsdb.h"
26 #include "nbt_server/wins/winsserver.h"
27 #include "librpc/gen_ndr/ndr_nbt.h"
28 #include "system/time.h"
29 #include "libcli/composite/composite.h"
30 #include "smbd/service_task.h"
31 #include "system/network.h"
32 #include "lib/socket/socket.h"
33 #include "lib/socket/netif.h"
34 #include "lib/ldb/include/ldb.h"
35 #include "param/param.h"
36 #include "libcli/resolve/resolve.h"
39 work out the ttl we will use given a client requested ttl
41 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
43 ttl = MIN(ttl, winssrv->config.max_renew_interval);
44 ttl = MAX(ttl, winssrv->config.min_renew_interval);
45 return ttl;
48 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
50 /* this copes with the nasty hack that is the type 0x1c name */
51 if (name->type == NBT_NAME_LOGON) {
52 return WREPL_TYPE_SGROUP;
54 if (nb_flags & NBT_NM_GROUP) {
55 return WREPL_TYPE_GROUP;
57 if (mhomed) {
58 return WREPL_TYPE_MHOMED;
60 return WREPL_TYPE_UNIQUE;
64 register a new name with WINS
66 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
67 struct nbt_name_packet *packet,
68 const struct socket_address *src,
69 enum wrepl_name_type type)
71 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
72 struct nbtd_interface);
73 struct wins_server *winssrv = iface->nbtsrv->winssrv;
74 struct nbt_name *name = &packet->questions[0].name;
75 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
76 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
77 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
78 struct winsdb_record rec;
79 enum wrepl_name_node node;
81 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
82 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
84 node = WREPL_NODE_NBT_FLAGS(nb_flags);
86 rec.name = name;
87 rec.type = type;
88 rec.state = WREPL_STATE_ACTIVE;
89 rec.node = node;
90 rec.is_static = false;
91 rec.expire_time = time(NULL) + ttl;
92 rec.version = 0; /* will be allocated later */
93 rec.wins_owner = NULL; /* will be set later */
94 rec.registered_by = src->addr;
95 rec.addresses = winsdb_addr_list_make(packet);
96 if (rec.addresses == NULL) return NBT_RCODE_SVR;
98 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
99 &rec, rec.addresses,
100 address,
101 winssrv->wins_db->local_owner,
102 rec.expire_time,
103 true);
104 if (rec.addresses == NULL) return NBT_RCODE_SVR;
106 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
107 nbt_name_string(packet, name), rec.addresses[0]->address));
109 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
114 update the ttl on an existing record
116 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
117 struct nbt_name_packet *packet,
118 struct winsdb_record *rec,
119 struct winsdb_addr *winsdb_addr,
120 const struct socket_address *src)
122 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
123 struct nbtd_interface);
124 struct wins_server *winssrv = iface->nbtsrv->winssrv;
125 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
126 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
127 uint32_t modify_flags = 0;
129 rec->expire_time = time(NULL) + ttl;
130 rec->registered_by = src->addr;
132 if (winsdb_addr) {
133 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
134 rec, rec->addresses,
135 winsdb_addr->address,
136 winssrv->wins_db->local_owner,
137 rec->expire_time,
138 true);
139 if (rec->addresses == NULL) return NBT_RCODE_SVR;
142 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
143 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
146 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
147 nbt_name_string(packet, rec->name), address));
149 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
153 do a sgroup merge
155 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
156 struct nbt_name_packet *packet,
157 struct winsdb_record *rec,
158 const char *address,
159 const struct socket_address *src)
161 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
162 struct nbtd_interface);
163 struct wins_server *winssrv = iface->nbtsrv->winssrv;
164 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
166 rec->expire_time = time(NULL) + ttl;
167 rec->registered_by = src->addr;
169 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
170 rec, rec->addresses,
171 address,
172 winssrv->wins_db->local_owner,
173 rec->expire_time,
174 true);
175 if (rec->addresses == NULL) return NBT_RCODE_SVR;
177 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
178 nbt_name_string(packet, rec->name), address));
180 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
183 struct wack_state {
184 struct wins_server *winssrv;
185 struct nbt_name_socket *nbtsock;
186 struct nbt_name_packet *request_packet;
187 struct winsdb_record *rec;
188 struct socket_address *src;
189 const char *reg_address;
190 enum wrepl_name_type new_type;
191 struct wins_challenge_io io;
192 NTSTATUS status;
196 deny a registration request
198 static void wins_wack_deny(struct wack_state *s)
200 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
201 s->src, NBT_RCODE_ACT);
202 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
203 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
204 talloc_free(s);
208 allow a registration request
210 static void wins_wack_allow(struct wack_state *s)
212 NTSTATUS status;
213 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
214 struct winsdb_record *rec = s->rec, *rec2;
215 uint32_t i,j;
217 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
218 if (!NT_STATUS_IS_OK(status) ||
219 rec2->version != rec->version ||
220 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
221 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
222 nbt_name_string(s, rec->name)));
223 wins_wack_deny(s);
224 return;
228 * if the old name owner doesn't hold the name anymore
229 * handle the request as new registration for the new name owner
231 if (!NT_STATUS_IS_OK(s->status)) {
232 uint8_t rcode;
234 winsdb_delete(s->winssrv->wins_db, rec);
235 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
236 if (rcode != NBT_RCODE_OK) {
237 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
238 nbt_name_string(s, rec->name)));
239 wins_wack_deny(s);
240 return;
242 goto done;
245 rec->expire_time = time(NULL) + ttl;
246 rec->registered_by = s->src->addr;
249 * now remove all addresses that're the client doesn't hold anymore
250 * and update the time stamp and owner for the ownes that are still there
252 for (i=0; rec->addresses[i]; i++) {
253 bool found = false;
254 for (j=0; j < s->io.out.num_addresses; j++) {
255 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
257 found = true;
258 break;
260 if (found) {
261 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
262 rec, rec->addresses,
263 s->reg_address,
264 s->winssrv->wins_db->local_owner,
265 rec->expire_time,
266 true);
267 if (rec->addresses == NULL) goto failed;
268 continue;
271 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
274 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
275 rec, rec->addresses,
276 s->reg_address,
277 s->winssrv->wins_db->local_owner,
278 rec->expire_time,
279 true);
280 if (rec->addresses == NULL) goto failed;
282 /* if we have more than one address, this becomes implicit a MHOMED record */
283 if (winsdb_addr_list_length(rec->addresses) > 1) {
284 rec->type = WREPL_TYPE_MHOMED;
287 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
289 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
290 nbt_name_string(s, rec->name), s->reg_address));
292 done:
293 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
294 s->src, NBT_RCODE_OK);
295 failed:
296 talloc_free(s);
300 called when a name query to a current owner completes
302 static void wack_wins_challenge_handler(struct composite_context *c_req)
304 struct wack_state *s = talloc_get_type(c_req->async.private_data,
305 struct wack_state);
306 bool found;
307 uint32_t i;
309 s->status = wins_challenge_recv(c_req, s, &s->io);
312 * if the owner denies it holds the name, then allow
313 * the registration
315 if (!NT_STATUS_IS_OK(s->status)) {
316 wins_wack_allow(s);
317 return;
320 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
321 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
322 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
323 wins_wack_deny(s);
324 return;
328 * if the owner still wants the name and doesn't reply
329 * with the address trying to be registered, then deny
330 * the registration
332 found = false;
333 for (i=0; i < s->io.out.num_addresses; i++) {
334 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
336 found = true;
337 break;
339 if (!found) {
340 wins_wack_deny(s);
341 return;
344 wins_wack_allow(s);
345 return;
350 a client has asked to register a unique name that someone else owns. We
351 need to ask each of the current owners if they still want it. If they do
352 then reject the registration, otherwise allow it
354 static void wins_register_wack(struct nbt_name_socket *nbtsock,
355 struct nbt_name_packet *packet,
356 struct winsdb_record *rec,
357 struct socket_address *src,
358 enum wrepl_name_type new_type)
360 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
361 struct nbtd_interface);
362 struct wins_server *winssrv = iface->nbtsrv->winssrv;
363 struct wack_state *s;
364 struct composite_context *c_req;
365 uint32_t ttl;
367 s = talloc_zero(nbtsock, struct wack_state);
368 if (s == NULL) goto failed;
370 /* package up the state variables for this wack request */
371 s->winssrv = winssrv;
372 s->nbtsock = nbtsock;
373 s->request_packet = talloc_steal(s, packet);
374 s->rec = talloc_steal(s, rec);
375 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
376 s->new_type = new_type;
377 s->src = src;
378 if (talloc_reference(s, src) == NULL) goto failed;
380 s->io.in.nbtd_server = iface->nbtsrv;
381 s->io.in.nbt_port = lp_nbt_port(iface->nbtsrv->task->lp_ctx);
382 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
383 s->io.in.name = rec->name;
384 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
385 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
386 if (s->io.in.addresses == NULL) goto failed;
389 * send a WACK to the client, specifying the maximum time it could
390 * take to check with the owner, plus some slack
392 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
393 nbtd_wack_reply(nbtsock, packet, src, ttl);
396 * send the challenge to the old addresses
398 c_req = wins_challenge_send(s, &s->io);
399 if (c_req == NULL) goto failed;
401 c_req->async.fn = wack_wins_challenge_handler;
402 c_req->async.private_data = s;
403 return;
405 failed:
406 talloc_free(s);
407 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
411 register a name
413 static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
414 struct nbt_name_packet *packet,
415 struct socket_address *src)
417 NTSTATUS status;
418 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
419 struct nbtd_interface);
420 struct wins_server *winssrv = iface->nbtsrv->winssrv;
421 struct nbt_name *name = &packet->questions[0].name;
422 struct winsdb_record *rec;
423 uint8_t rcode = NBT_RCODE_OK;
424 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
425 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
426 bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
427 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
428 struct winsdb_addr *winsdb_addr = NULL;
431 * as a special case, the local master browser name is always accepted
432 * for registration, but never stored, but w2k3 stores it if it's registered
433 * as a group name, (but a query for the 0x1D name still returns not found!)
435 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
436 rcode = NBT_RCODE_OK;
437 goto done;
440 /* w2k3 refuses 0x1B names with marked as group */
441 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
442 rcode = NBT_RCODE_RFS;
443 goto done;
446 /* w2k3 refuses 0x1C names with out marked as group */
447 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
448 rcode = NBT_RCODE_RFS;
449 goto done;
452 /* w2k3 refuses 0x1E names with out marked as group */
453 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
454 rcode = NBT_RCODE_RFS;
455 goto done;
458 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
459 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
460 rcode = wins_register_new(nbtsock, packet, src, new_type);
461 goto done;
462 } else if (!NT_STATUS_IS_OK(status)) {
463 rcode = NBT_RCODE_SVR;
464 goto done;
465 } else if (rec->is_static) {
466 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
467 rcode = NBT_RCODE_OK;
468 goto done;
470 rcode = NBT_RCODE_ACT;
471 goto done;
474 if (rec->type == WREPL_TYPE_GROUP) {
475 if (new_type != WREPL_TYPE_GROUP) {
476 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
477 " while a normal group is already there\n",
478 nbt_name_string(packet, name), new_type));
479 rcode = NBT_RCODE_ACT;
480 goto done;
483 if (rec->state == WREPL_STATE_ACTIVE) {
484 /* TODO: is this correct? */
485 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
486 goto done;
489 /* TODO: is this correct? */
490 winsdb_delete(winssrv->wins_db, rec);
491 rcode = wins_register_new(nbtsock, packet, src, new_type);
492 goto done;
495 if (rec->state != WREPL_STATE_ACTIVE) {
496 winsdb_delete(winssrv->wins_db, rec);
497 rcode = wins_register_new(nbtsock, packet, src, new_type);
498 goto done;
501 switch (rec->type) {
502 case WREPL_TYPE_UNIQUE:
503 case WREPL_TYPE_MHOMED:
505 * if its an active unique name, and the registration is for a group, then
506 * see if the unique name owner still wants the name
507 * TODO: is this correct?
509 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
510 wins_register_wack(nbtsock, packet, rec, src, new_type);
511 return;
515 * if the registration is for an address that is currently active, then
516 * just update the expiry time of the record and the address
518 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
519 if (winsdb_addr) {
520 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
521 goto done;
525 * we have to do a WACK to see if the current owner is willing
526 * to give up its claim
528 wins_register_wack(nbtsock, packet, rec, src, new_type);
529 return;
531 case WREPL_TYPE_GROUP:
532 /* this should not be reached as normal groups are handled above */
533 DEBUG(0,("BUG at %s\n",__location__));
534 rcode = NBT_RCODE_ACT;
535 goto done;
537 case WREPL_TYPE_SGROUP:
538 /* if the new record isn't also a special group, refuse the registration */
539 if (new_type != WREPL_TYPE_SGROUP) {
540 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
541 " while a special group is already there\n",
542 nbt_name_string(packet, name), new_type));
543 rcode = NBT_RCODE_ACT;
544 goto done;
548 * if the registration is for an address that is currently active, then
549 * just update the expiry time of the record and the address
551 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
552 if (winsdb_addr) {
553 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
554 goto done;
557 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
558 goto done;
561 done:
562 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
565 static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
567 uint32_t i, j, match=0;
568 uint8_t *p1, *p2;
570 p1 = (uint8_t *)&ip1.s_addr;
571 p2 = (uint8_t *)&ip2.s_addr;
573 for (i=0; i<4; i++) {
574 if (p1[i] != p2[i]) break;
575 match += 8;
578 if (i==4) return match;
580 for (j=0; j<8; j++) {
581 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
582 break;
583 match++;
586 return match;
589 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
590 void *p2,/* (const char **) */
591 struct socket_address *src)
593 const char *a1 = (const char *)*(const char **)p1;
594 const char *a2 = (const char *)*(const char **)p2;
595 uint32_t match_bits1;
596 uint32_t match_bits2;
598 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
599 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
601 return match_bits2 - match_bits1;
604 static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
605 const char **addresses, struct socket_address *src)
607 const char *mask;
608 const char *tmp;
609 uint32_t num_addrs;
610 uint32_t idx, sidx;
611 int r;
613 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
615 if (num_addrs <= 1) return; /* nothing to do */
617 /* first sort the addresses depending on the matching to the client */
618 ldb_qsort(addresses, num_addrs , sizeof(addresses[0]),
619 src, (ldb_qsort_cmp_fn_t)nbtd_wins_randomize1Clist_sort);
621 mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
622 if (!mask) {
623 mask = "255.255.255.0";
627 * choose a random address to be the first in the response to the client,
628 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
630 r = random();
631 idx = sidx = r % num_addrs;
633 while (1) {
634 bool same;
636 /* if the current one is in the same subnet, use it */
637 same = iface_same_net(addresses[idx], src->addr, mask);
638 if (same) {
639 sidx = idx;
640 break;
643 /* we need to check for idx == 0, after checking for the same net */
644 if (idx == 0) break;
646 * if we haven't found an address in the same subnet, search in ones
647 * which match the client more
649 * some notes:
651 * it's not "idx = idx % r" but "idx = r % idx"
652 * because in "a % b" b is the allowed range
653 * and b-1 is the maximum possible result, so it must be decreasing
654 * and the above idx == 0 check breaks the while(1) loop.
656 idx = r % idx;
659 /* note sidx == 0 is also valid here ... */
660 tmp = addresses[0];
661 addresses[0] = addresses[sidx];
662 addresses[sidx] = tmp;
666 query a name
668 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
669 struct nbt_name_socket *nbtsock,
670 struct nbt_name_packet *packet,
671 struct socket_address *src)
673 NTSTATUS status;
674 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
675 struct nbtd_interface);
676 struct wins_server *winssrv = iface->nbtsrv->winssrv;
677 struct nbt_name *name = &packet->questions[0].name;
678 struct winsdb_record *rec;
679 struct winsdb_record *rec_1b = NULL;
680 const char **addresses;
681 const char **addresses_1b = NULL;
682 uint16_t nb_flags = 0;
684 if (name->type == NBT_NAME_MASTER) {
685 goto notfound;
689 * w2k3 returns the first address of the 0x1B record as first address
690 * to a 0x1C query
692 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
694 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
695 * Typ: Daten REG_DWORD
696 * Value: 0 = deactivated, 1 = activated
698 if (name->type == NBT_NAME_LOGON &&
699 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
700 struct nbt_name name_1b;
702 name_1b = *name;
703 name_1b.type = NBT_NAME_PDC;
705 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
706 if (NT_STATUS_IS_OK(status)) {
707 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
711 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
712 if (!NT_STATUS_IS_OK(status)) {
713 if (!lp_wins_dns_proxy(lp_ctx)) {
714 goto notfound;
717 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
718 goto notfound;
721 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
722 return;
726 * for group's we always reply with
727 * 255.255.255.255 as address, even if
728 * the record is released or tombstoned
730 if (rec->type == WREPL_TYPE_GROUP) {
731 addresses = str_list_add(NULL, "255.255.255.255");
732 talloc_steal(packet, addresses);
733 if (!addresses) {
734 goto notfound;
736 nb_flags |= NBT_NM_GROUP;
737 goto found;
740 if (rec->state != WREPL_STATE_ACTIVE) {
741 goto notfound;
744 addresses = winsdb_addr_string_list(packet, rec->addresses);
745 if (!addresses) {
746 goto notfound;
750 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
751 * first 0x1B address as first address
753 if (addresses_1b && addresses_1b[0]) {
754 const char **addresses_1c = addresses;
755 uint32_t i;
756 uint32_t num_addrs;
758 addresses = str_list_add(NULL, addresses_1b[0]);
759 if (!addresses) {
760 goto notfound;
762 talloc_steal(packet, addresses);
763 num_addrs = 1;
765 for (i=0; addresses_1c[i]; i++) {
766 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
769 * stop when we already have 25 addresses
771 if (num_addrs >= 25) break;
773 num_addrs++;
774 addresses = str_list_add(addresses, addresses_1c[i]);
775 if (!addresses) {
776 goto notfound;
781 if (rec->type == WREPL_TYPE_SGROUP) {
782 nb_flags |= NBT_NM_GROUP;
783 } else {
784 nb_flags |= (rec->node <<13);
788 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
790 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
791 * Typ: Daten REG_DWORD
792 * Value: 0 = deactivated, 1 = activated
794 if (name->type == NBT_NAME_LOGON &&
795 lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
796 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
799 found:
800 nbtd_name_query_reply(nbtsock, packet, src, name,
801 0, nb_flags, addresses);
802 return;
804 notfound:
805 nbtd_negative_name_query_reply(nbtsock, packet, src);
809 release a name
811 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
812 struct nbt_name_packet *packet,
813 struct socket_address *src)
815 NTSTATUS status;
816 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
817 struct nbtd_interface);
818 struct wins_server *winssrv = iface->nbtsrv->winssrv;
819 struct nbt_name *name = &packet->questions[0].name;
820 struct winsdb_record *rec;
821 uint32_t modify_flags = 0;
822 uint8_t ret;
824 if (name->type == NBT_NAME_MASTER) {
825 goto done;
828 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
829 if (!NT_STATUS_IS_OK(status)) {
830 goto done;
833 if (rec->is_static) {
834 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
835 goto done;
837 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
838 return;
841 if (rec->state != WREPL_STATE_ACTIVE) {
842 goto done;
846 * TODO: do we need to check if
847 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
848 * here?
852 * we only allow releases from an owner - other releases are
853 * silently ignored
855 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
856 int i;
857 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
858 DEBUGADD(4, ("Registered Addresses: \n"));
859 for (i=0; rec->addresses && rec->addresses[i]; i++) {
860 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
862 goto done;
865 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
867 switch (rec->type) {
868 case WREPL_TYPE_UNIQUE:
869 rec->state = WREPL_STATE_RELEASED;
870 break;
872 case WREPL_TYPE_GROUP:
873 rec->state = WREPL_STATE_RELEASED;
874 break;
876 case WREPL_TYPE_SGROUP:
877 winsdb_addr_list_remove(rec->addresses, src->addr);
878 /* TODO: do we need to take the ownership here? */
879 if (winsdb_addr_list_length(rec->addresses) == 0) {
880 rec->state = WREPL_STATE_RELEASED;
882 break;
884 case WREPL_TYPE_MHOMED:
885 winsdb_addr_list_remove(rec->addresses, src->addr);
886 /* TODO: do we need to take the ownership here? */
887 if (winsdb_addr_list_length(rec->addresses) == 0) {
888 rec->state = WREPL_STATE_RELEASED;
890 break;
893 if (rec->state == WREPL_STATE_RELEASED) {
895 * if we're not the owner, we need to take the owner ship
896 * and make the record tombstone, but expire after
897 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
898 * like for normal tombstone records.
899 * This is to replicate the record directly to the original owner,
900 * where the record is still active
902 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
903 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
904 } else {
905 rec->state = WREPL_STATE_TOMBSTONE;
906 rec->expire_time= time(NULL) +
907 winssrv->config.tombstone_interval +
908 winssrv->config.tombstone_timeout;
909 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
913 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
914 if (ret != NBT_RCODE_OK) {
915 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
916 nbt_name_string(rec, rec->name), src->addr, ret));
918 done:
919 /* we match w2k3 by always giving a positive reply to name releases. */
920 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
925 answer a name query
927 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
928 struct nbt_name_packet *packet,
929 struct socket_address *src)
931 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
932 struct nbtd_interface);
933 struct wins_server *winssrv = iface->nbtsrv->winssrv;
934 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
935 return;
938 switch (packet->operation & NBT_OPCODE) {
939 case NBT_OPCODE_QUERY:
940 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
941 break;
943 case NBT_OPCODE_REGISTER:
944 case NBT_OPCODE_REFRESH:
945 case NBT_OPCODE_REFRESH2:
946 case NBT_OPCODE_MULTI_HOME_REG:
947 nbtd_winsserver_register(nbtsock, packet, src);
948 break;
950 case NBT_OPCODE_RELEASE:
951 nbtd_winsserver_release(nbtsock, packet, src);
952 break;
958 startup the WINS server, if configured
960 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
962 uint32_t tmp;
963 const char *owner;
965 if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
966 nbtsrv->winssrv = NULL;
967 return NT_STATUS_OK;
970 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
971 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
973 nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
974 nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
975 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
976 nbtsrv->winssrv->config.tombstone_interval = tmp;
977 tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
978 nbtsrv->winssrv->config.tombstone_timeout = tmp;
980 owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
982 if (owner == NULL) {
983 struct interface *ifaces;
984 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
985 owner = iface_n_ip(ifaces, 0);
988 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx,
989 nbtsrv->task->lp_ctx,
990 owner, WINSDB_HANDLE_CALLER_NBTD);
991 if (!nbtsrv->winssrv->wins_db) {
992 return NT_STATUS_INTERNAL_DB_ERROR;
995 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
997 return NT_STATUS_OK;