source: trunk/server/source4/nbt_server/wins/winsserver.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 31.4 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 core wins server handling
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 3 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, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "includes.h"
24#include "lib/util/dlinklist.h"
25#include "nbt_server/nbt_server.h"
26#include "nbt_server/wins/winsdb.h"
27#include "nbt_server/wins/winsserver.h"
28#include "librpc/gen_ndr/ndr_nbt.h"
29#include "system/time.h"
30#include "libcli/composite/composite.h"
31#include "smbd/service_task.h"
32#include "system/network.h"
33#include "lib/socket/socket.h"
34#include "lib/socket/netif.h"
35#include <ldb.h>
36#include "param/param.h"
37#include "libcli/resolve/resolve.h"
38#include "lib/util/util_net.h"
39
40/*
41 work out the ttl we will use given a client requested ttl
42*/
43uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
44{
45 ttl = MIN(ttl, winssrv->config.max_renew_interval);
46 ttl = MAX(ttl, winssrv->config.min_renew_interval);
47 return ttl;
48}
49
50static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, bool mhomed)
51{
52 /* this copes with the nasty hack that is the type 0x1c name */
53 if (name->type == NBT_NAME_LOGON) {
54 return WREPL_TYPE_SGROUP;
55 }
56 if (nb_flags & NBT_NM_GROUP) {
57 return WREPL_TYPE_GROUP;
58 }
59 if (mhomed) {
60 return WREPL_TYPE_MHOMED;
61 }
62 return WREPL_TYPE_UNIQUE;
63}
64
65/*
66 register a new name with WINS
67*/
68static uint8_t wins_register_new(struct nbt_name_socket *nbtsock,
69 struct nbt_name_packet *packet,
70 const struct socket_address *src,
71 enum wrepl_name_type type)
72{
73 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
74 struct nbtd_interface);
75 struct wins_server *winssrv = iface->nbtsrv->winssrv;
76 struct nbt_name *name = &packet->questions[0].name;
77 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
78 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
79 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
80 struct winsdb_record rec;
81 enum wrepl_name_node node;
82
83#define WREPL_NODE_NBT_FLAGS(nb_flags) \
84 ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
85
86 node = WREPL_NODE_NBT_FLAGS(nb_flags);
87
88 rec.name = name;
89 rec.type = type;
90 rec.state = WREPL_STATE_ACTIVE;
91 rec.node = node;
92 rec.is_static = false;
93 rec.expire_time = time(NULL) + ttl;
94 rec.version = 0; /* will be allocated later */
95 rec.wins_owner = NULL; /* will be set later */
96 rec.registered_by = src->addr;
97 rec.addresses = winsdb_addr_list_make(packet);
98 if (rec.addresses == NULL) return NBT_RCODE_SVR;
99
100 rec.addresses = winsdb_addr_list_add(winssrv->wins_db,
101 &rec, rec.addresses,
102 address,
103 winssrv->wins_db->local_owner,
104 rec.expire_time,
105 true);
106 if (rec.addresses == NULL) return NBT_RCODE_SVR;
107
108 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
109 nbt_name_string(packet, name), rec.addresses[0]->address));
110
111 return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
112}
113
114
115/*
116 update the ttl on an existing record
117*/
118static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock,
119 struct nbt_name_packet *packet,
120 struct winsdb_record *rec,
121 struct winsdb_addr *winsdb_addr,
122 const struct socket_address *src)
123{
124 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
125 struct nbtd_interface);
126 struct wins_server *winssrv = iface->nbtsrv->winssrv;
127 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
128 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
129 uint32_t modify_flags = 0;
130
131 rec->expire_time = time(NULL) + ttl;
132 rec->registered_by = src->addr;
133
134 if (winsdb_addr) {
135 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
136 rec, rec->addresses,
137 winsdb_addr->address,
138 winssrv->wins_db->local_owner,
139 rec->expire_time,
140 true);
141 if (rec->addresses == NULL) return NBT_RCODE_SVR;
142 }
143
144 if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
145 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
146 }
147
148 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
149 nbt_name_string(packet, rec->name), address));
150
151 return winsdb_modify(winssrv->wins_db, rec, modify_flags);
152}
153
154/*
155 do a sgroup merge
156*/
157static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock,
158 struct nbt_name_packet *packet,
159 struct winsdb_record *rec,
160 const char *address,
161 const struct socket_address *src)
162{
163 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
164 struct nbtd_interface);
165 struct wins_server *winssrv = iface->nbtsrv->winssrv;
166 uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
167
168 rec->expire_time = time(NULL) + ttl;
169 rec->registered_by = src->addr;
170
171 rec->addresses = winsdb_addr_list_add(winssrv->wins_db,
172 rec, rec->addresses,
173 address,
174 winssrv->wins_db->local_owner,
175 rec->expire_time,
176 true);
177 if (rec->addresses == NULL) return NBT_RCODE_SVR;
178
179 DEBUG(5,("WINS: sgroup merge of %s at %s\n",
180 nbt_name_string(packet, rec->name), address));
181
182 return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
183}
184
185struct nbtd_wins_wack_state {
186 struct nbtd_wins_wack_state *prev, *next;
187 struct wins_server *winssrv;
188 struct nbt_name_socket *nbtsock;
189 struct nbtd_interface *iface;
190 struct nbt_name_packet *request_packet;
191 struct winsdb_record *rec;
192 struct socket_address *src;
193 const char *reg_address;
194 enum wrepl_name_type new_type;
195 struct wins_challenge_io io;
196 NTSTATUS status;
197};
198
199static int nbtd_wins_wack_state_destructor(struct nbtd_wins_wack_state *s)
200{
201 DLIST_REMOVE(s->iface->wack_queue, s);
202 return 0;
203}
204
205static bool wins_check_wack_queue(struct nbtd_interface *iface,
206 struct nbt_name_packet *packet,
207 struct socket_address *src)
208{
209 struct nbtd_wins_wack_state *s;
210
211 for (s= iface->wack_queue; s; s = s->next) {
212 if (packet->name_trn_id != s->request_packet->name_trn_id) {
213 continue;
214 }
215 if (packet->operation != s->request_packet->operation) {
216 continue;
217 }
218 if (src->port != s->src->port) {
219 continue;
220 }
221 if (strcmp(src->addr, s->src->addr) != 0) {
222 continue;
223 }
224
225 return true;
226 }
227
228 return false;
229}
230
231/*
232 deny a registration request
233*/
234static void wins_wack_deny(struct nbtd_wins_wack_state *s)
235{
236 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
237 s->src, NBT_RCODE_ACT);
238 DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
239 nbt_name_string(s, s->rec->name), s->src->addr, s->src->port));
240 talloc_free(s);
241}
242
243/*
244 allow a registration request
245*/
246static void wins_wack_allow(struct nbtd_wins_wack_state *s)
247{
248 NTSTATUS status;
249 uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
250 struct winsdb_record *rec = s->rec, *rec2;
251 uint32_t i,j;
252
253 status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
254 if (!NT_STATUS_IS_OK(status) ||
255 rec2->version != rec->version ||
256 strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
257 DEBUG(5,("WINS: record %s changed during WACK - failing registration\n",
258 nbt_name_string(s, rec->name)));
259 wins_wack_deny(s);
260 return;
261 }
262
263 /*
264 * if the old name owner doesn't hold the name anymore
265 * handle the request as new registration for the new name owner
266 */
267 if (!NT_STATUS_IS_OK(s->status)) {
268 uint8_t rcode;
269
270 winsdb_delete(s->winssrv->wins_db, rec);
271 rcode = wins_register_new(s->nbtsock, s->request_packet, s->src, s->new_type);
272 if (rcode != NBT_RCODE_OK) {
273 DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
274 nbt_name_string(s, rec->name)));
275 wins_wack_deny(s);
276 return;
277 }
278 goto done;
279 }
280
281 rec->expire_time = time(NULL) + ttl;
282 rec->registered_by = s->src->addr;
283
284 /*
285 * now remove all addresses that the client doesn't hold anymore
286 * and update the time stamp and owner for the ones that are still there
287 */
288 for (i=0; rec->addresses[i]; i++) {
289 bool found = false;
290 for (j=0; j < s->io.out.num_addresses; j++) {
291 if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
292
293 found = true;
294 break;
295 }
296 if (found) {
297 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
298 rec, rec->addresses,
299 s->reg_address,
300 s->winssrv->wins_db->local_owner,
301 rec->expire_time,
302 true);
303 if (rec->addresses == NULL) goto failed;
304 continue;
305 }
306
307 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
308 }
309
310 rec->addresses = winsdb_addr_list_add(s->winssrv->wins_db,
311 rec, rec->addresses,
312 s->reg_address,
313 s->winssrv->wins_db->local_owner,
314 rec->expire_time,
315 true);
316 if (rec->addresses == NULL) goto failed;
317
318 /* if we have more than one address, this becomes implicit a MHOMED record */
319 if (winsdb_addr_list_length(rec->addresses) > 1) {
320 rec->type = WREPL_TYPE_MHOMED;
321 }
322
323 winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
324
325 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
326 nbt_name_string(s, rec->name), s->reg_address));
327
328done:
329 nbtd_name_registration_reply(s->nbtsock, s->request_packet,
330 s->src, NBT_RCODE_OK);
331failed:
332 talloc_free(s);
333}
334
335/*
336 called when a name query to a current owner completes
337*/
338static void wack_wins_challenge_handler(struct composite_context *c_req)
339{
340 struct nbtd_wins_wack_state *s = talloc_get_type(c_req->async.private_data,
341 struct nbtd_wins_wack_state);
342 bool found;
343 uint32_t i;
344
345 s->status = wins_challenge_recv(c_req, s, &s->io);
346
347 /*
348 * if the owner denies it holds the name, then allow
349 * the registration
350 */
351 if (!NT_STATUS_IS_OK(s->status)) {
352 wins_wack_allow(s);
353 return;
354 }
355
356 if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
357 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
358 nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
359 wins_wack_deny(s);
360 return;
361 }
362
363 /*
364 * if the owner still wants the name and doesn't reply
365 * with the address trying to be registered, then deny
366 * the registration
367 */
368 found = false;
369 for (i=0; i < s->io.out.num_addresses; i++) {
370 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
371
372 found = true;
373 break;
374 }
375 if (!found) {
376 wins_wack_deny(s);
377 return;
378 }
379
380 wins_wack_allow(s);
381 return;
382}
383
384
385/*
386 a client has asked to register a unique name that someone else owns. We
387 need to ask each of the current owners if they still want it. If they do
388 then reject the registration, otherwise allow it
389*/
390static void wins_register_wack(struct nbt_name_socket *nbtsock,
391 struct nbt_name_packet *packet,
392 struct winsdb_record *rec,
393 struct socket_address *src,
394 enum wrepl_name_type new_type)
395{
396 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
397 struct nbtd_interface);
398 struct wins_server *winssrv = iface->nbtsrv->winssrv;
399 struct nbtd_wins_wack_state *s;
400 struct composite_context *c_req;
401 uint32_t ttl;
402
403 s = talloc_zero(nbtsock, struct nbtd_wins_wack_state);
404 if (s == NULL) goto failed;
405
406 /* package up the state variables for this wack request */
407 s->winssrv = winssrv;
408 s->nbtsock = nbtsock;
409 s->iface = iface;
410 s->request_packet = talloc_steal(s, packet);
411 s->rec = talloc_steal(s, rec);
412 s->reg_address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
413 s->new_type = new_type;
414 s->src = src;
415 if (talloc_reference(s, src) == NULL) goto failed;
416
417 s->io.in.nbtd_server = iface->nbtsrv;
418 s->io.in.nbt_port = lpcfg_nbt_port(iface->nbtsrv->task->lp_ctx);
419 s->io.in.event_ctx = iface->nbtsrv->task->event_ctx;
420 s->io.in.name = rec->name;
421 s->io.in.num_addresses = winsdb_addr_list_length(rec->addresses);
422 s->io.in.addresses = winsdb_addr_string_list(s, rec->addresses);
423 if (s->io.in.addresses == NULL) goto failed;
424
425 DLIST_ADD_END(iface->wack_queue, s, struct nbtd_wins_wack_state *);
426
427 talloc_set_destructor(s, nbtd_wins_wack_state_destructor);
428
429 /*
430 * send a WACK to the client, specifying the maximum time it could
431 * take to check with the owner, plus some slack
432 */
433 ttl = 5 + 4 * winsdb_addr_list_length(rec->addresses);
434 nbtd_wack_reply(nbtsock, packet, src, ttl);
435
436 /*
437 * send the challenge to the old addresses
438 */
439 c_req = wins_challenge_send(s, &s->io);
440 if (c_req == NULL) goto failed;
441
442 c_req->async.fn = wack_wins_challenge_handler;
443 c_req->async.private_data = s;
444 return;
445
446failed:
447 talloc_free(s);
448 nbtd_name_registration_reply(nbtsock, packet, src, NBT_RCODE_SVR);
449}
450
451/*
452 register a name
453*/
454static void nbtd_winsserver_register(struct nbt_name_socket *nbtsock,
455 struct nbt_name_packet *packet,
456 struct socket_address *src)
457{
458 NTSTATUS status;
459 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
460 struct nbtd_interface);
461 struct wins_server *winssrv = iface->nbtsrv->winssrv;
462 struct nbt_name *name = &packet->questions[0].name;
463 struct winsdb_record *rec;
464 uint8_t rcode = NBT_RCODE_OK;
465 uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
466 const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
467 bool mhomed = ((packet->operation & NBT_OPCODE) == NBT_OPCODE_MULTI_HOME_REG);
468 enum wrepl_name_type new_type = wrepl_type(nb_flags, name, mhomed);
469 struct winsdb_addr *winsdb_addr = NULL;
470 bool duplicate_packet;
471
472 /*
473 * as a special case, the local master browser name is always accepted
474 * for registration, but never stored, but w2k3 stores it if it's registered
475 * as a group name, (but a query for the 0x1D name still returns not found!)
476 */
477 if (name->type == NBT_NAME_MASTER && !(nb_flags & NBT_NM_GROUP)) {
478 rcode = NBT_RCODE_OK;
479 goto done;
480 }
481
482 /* w2k3 refuses 0x1B names with marked as group */
483 if (name->type == NBT_NAME_PDC && (nb_flags & NBT_NM_GROUP)) {
484 rcode = NBT_RCODE_RFS;
485 goto done;
486 }
487
488 /* w2k3 refuses 0x1C names with out marked as group */
489 if (name->type == NBT_NAME_LOGON && !(nb_flags & NBT_NM_GROUP)) {
490 rcode = NBT_RCODE_RFS;
491 goto done;
492 }
493
494 /* w2k3 refuses 0x1E names with out marked as group */
495 if (name->type == NBT_NAME_BROWSER && !(nb_flags & NBT_NM_GROUP)) {
496 rcode = NBT_RCODE_RFS;
497 goto done;
498 }
499
500 if (name->scope && strlen(name->scope) > 237) {
501 rcode = NBT_RCODE_SVR;
502 goto done;
503 }
504
505 duplicate_packet = wins_check_wack_queue(iface, packet, src);
506 if (duplicate_packet) {
507 /* just ignore the packet */
508 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
509 src->addr, src->port));
510 return;
511 }
512
513 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
514 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
515 rcode = wins_register_new(nbtsock, packet, src, new_type);
516 goto done;
517 } else if (!NT_STATUS_IS_OK(status)) {
518 rcode = NBT_RCODE_SVR;
519 goto done;
520 } else if (rec->is_static) {
521 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
522 rcode = NBT_RCODE_OK;
523 goto done;
524 }
525 rcode = NBT_RCODE_ACT;
526 goto done;
527 }
528
529 if (rec->type == WREPL_TYPE_GROUP) {
530 if (new_type != WREPL_TYPE_GROUP) {
531 DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
532 " while a normal group is already there\n",
533 nbt_name_string(packet, name), new_type));
534 rcode = NBT_RCODE_ACT;
535 goto done;
536 }
537
538 if (rec->state == WREPL_STATE_ACTIVE) {
539 /* TODO: is this correct? */
540 rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
541 goto done;
542 }
543
544 /* TODO: is this correct? */
545 winsdb_delete(winssrv->wins_db, rec);
546 rcode = wins_register_new(nbtsock, packet, src, new_type);
547 goto done;
548 }
549
550 if (rec->state != WREPL_STATE_ACTIVE) {
551 winsdb_delete(winssrv->wins_db, rec);
552 rcode = wins_register_new(nbtsock, packet, src, new_type);
553 goto done;
554 }
555
556 switch (rec->type) {
557 case WREPL_TYPE_UNIQUE:
558 case WREPL_TYPE_MHOMED:
559 /*
560 * if its an active unique name, and the registration is for a group, then
561 * see if the unique name owner still wants the name
562 * TODO: is this correct?
563 */
564 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
565 wins_register_wack(nbtsock, packet, rec, src, new_type);
566 return;
567 }
568
569 /*
570 * if the registration is for an address that is currently active, then
571 * just update the expiry time of the record and the address
572 */
573 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
574 if (winsdb_addr) {
575 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
576 goto done;
577 }
578
579 /*
580 * we have to do a WACK to see if the current owner is willing
581 * to give up its claim
582 */
583 wins_register_wack(nbtsock, packet, rec, src, new_type);
584 return;
585
586 case WREPL_TYPE_GROUP:
587 /* this should not be reached as normal groups are handled above */
588 DEBUG(0,("BUG at %s\n",__location__));
589 rcode = NBT_RCODE_ACT;
590 goto done;
591
592 case WREPL_TYPE_SGROUP:
593 /* if the new record isn't also a special group, refuse the registration */
594 if (new_type != WREPL_TYPE_SGROUP) {
595 DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
596 " while a special group is already there\n",
597 nbt_name_string(packet, name), new_type));
598 rcode = NBT_RCODE_ACT;
599 goto done;
600 }
601
602 /*
603 * if the registration is for an address that is currently active, then
604 * just update the expiry time of the record and the address
605 */
606 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
607 if (winsdb_addr) {
608 rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
609 goto done;
610 }
611
612 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
613 goto done;
614 }
615
616done:
617 nbtd_name_registration_reply(nbtsock, packet, src, rcode);
618}
619
620static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
621{
622 uint32_t i, j, match=0;
623 uint8_t *p1, *p2;
624
625 p1 = (uint8_t *)&ip1.s_addr;
626 p2 = (uint8_t *)&ip2.s_addr;
627
628 for (i=0; i<4; i++) {
629 if (p1[i] != p2[i]) break;
630 match += 8;
631 }
632
633 if (i==4) return match;
634
635 for (j=0; j<8; j++) {
636 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
637 break;
638 match++;
639 }
640
641 return match;
642}
643
644static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
645 void *p2,/* (const char **) */
646 struct socket_address *src)
647{
648 const char *a1 = (const char *)*(const char **)p1;
649 const char *a2 = (const char *)*(const char **)p2;
650 uint32_t match_bits1;
651 uint32_t match_bits2;
652
653 match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
654 match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
655
656 return match_bits2 - match_bits1;
657}
658
659static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
660 const char **addresses, struct socket_address *src)
661{
662 const char *mask;
663 const char *tmp;
664 uint32_t num_addrs;
665 uint32_t idx, sidx;
666 int r;
667
668 for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
669
670 if (num_addrs <= 1) return; /* nothing to do */
671
672 /* first sort the addresses depending on the matching to the client */
673 LDB_TYPESAFE_QSORT(addresses, num_addrs, src, nbtd_wins_randomize1Clist_sort);
674
675 mask = lpcfg_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
676 if (!mask) {
677 mask = "255.255.255.0";
678 }
679
680 /*
681 * choose a random address to be the first in the response to the client,
682 * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
683 */
684 r = random();
685 idx = sidx = r % num_addrs;
686
687 while (1) {
688 bool same;
689
690 /* if the current one is in the same subnet, use it */
691 same = iface_same_net(addresses[idx], src->addr, mask);
692 if (same) {
693 sidx = idx;
694 break;
695 }
696
697 /* we need to check for idx == 0, after checking for the same net */
698 if (idx == 0) break;
699 /*
700 * if we haven't found an address in the same subnet, search in ones
701 * which match the client more
702 *
703 * some notes:
704 *
705 * it's not "idx = idx % r" but "idx = r % idx"
706 * because in "a % b" b is the allowed range
707 * and b-1 is the maximum possible result, so it must be decreasing
708 * and the above idx == 0 check breaks the while(1) loop.
709 */
710 idx = r % idx;
711 }
712
713 /* note sidx == 0 is also valid here ... */
714 tmp = addresses[0];
715 addresses[0] = addresses[sidx];
716 addresses[sidx] = tmp;
717}
718
719/*
720 query a name
721*/
722static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
723 struct nbt_name_socket *nbtsock,
724 struct nbt_name_packet *packet,
725 struct socket_address *src)
726{
727 NTSTATUS status;
728 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
729 struct nbtd_interface);
730 struct wins_server *winssrv = iface->nbtsrv->winssrv;
731 struct nbt_name *name = &packet->questions[0].name;
732 struct winsdb_record *rec;
733 struct winsdb_record *rec_1b = NULL;
734 const char **addresses;
735 const char **addresses_1b = NULL;
736 uint16_t nb_flags = 0;
737
738 if (name->type == NBT_NAME_MASTER) {
739 goto notfound;
740 }
741
742 /*
743 * w2k3 returns the first address of the 0x1B record as first address
744 * to a 0x1C query
745 *
746 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
747 *
748 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
749 * Typ: Daten REG_DWORD
750 * Value: 0 = deactivated, 1 = activated
751 */
752 if (name->type == NBT_NAME_LOGON &&
753 lpcfg_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
754 struct nbt_name name_1b;
755
756 name_1b = *name;
757 name_1b.type = NBT_NAME_PDC;
758
759 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
760 if (NT_STATUS_IS_OK(status)) {
761 addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
762 }
763 }
764
765 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
766 if (!NT_STATUS_IS_OK(status)) {
767 if (!lpcfg_wins_dns_proxy(lp_ctx)) {
768 goto notfound;
769 }
770
771 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
772 goto notfound;
773 }
774
775 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
776 return;
777 }
778
779 /*
780 * for group's we always reply with
781 * 255.255.255.255 as address, even if
782 * the record is released or tombstoned
783 */
784 if (rec->type == WREPL_TYPE_GROUP) {
785 addresses = str_list_add(NULL, "255.255.255.255");
786 talloc_steal(packet, addresses);
787 if (!addresses) {
788 goto notfound;
789 }
790 nb_flags |= NBT_NM_GROUP;
791 goto found;
792 }
793
794 if (rec->state != WREPL_STATE_ACTIVE) {
795 goto notfound;
796 }
797
798 addresses = winsdb_addr_string_list(packet, rec->addresses);
799 if (!addresses) {
800 goto notfound;
801 }
802
803 /*
804 * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
805 * first 0x1B address as first address
806 */
807 if (addresses_1b && addresses_1b[0]) {
808 const char **addresses_1c = addresses;
809 uint32_t i;
810 uint32_t num_addrs;
811
812 addresses = str_list_add(NULL, addresses_1b[0]);
813 if (!addresses) {
814 goto notfound;
815 }
816 talloc_steal(packet, addresses);
817 num_addrs = 1;
818
819 for (i=0; addresses_1c[i]; i++) {
820 if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
821
822 /*
823 * stop when we already have 25 addresses
824 */
825 if (num_addrs >= 25) break;
826
827 num_addrs++;
828 addresses = str_list_add(addresses, addresses_1c[i]);
829 if (!addresses) {
830 goto notfound;
831 }
832 }
833 }
834
835 if (rec->type == WREPL_TYPE_SGROUP) {
836 nb_flags |= NBT_NM_GROUP;
837 } else {
838 nb_flags |= (rec->node <<13);
839 }
840
841 /*
842 * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
843 *
844 * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
845 * Typ: Daten REG_DWORD
846 * Value: 0 = deactivated, 1 = activated
847 */
848 if (name->type == NBT_NAME_LOGON &&
849 lpcfg_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
850 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
851 }
852
853found:
854 nbtd_name_query_reply(nbtsock, packet, src, name,
855 0, nb_flags, addresses);
856 return;
857
858notfound:
859 nbtd_negative_name_query_reply(nbtsock, packet, src);
860}
861
862/*
863 release a name
864*/
865static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock,
866 struct nbt_name_packet *packet,
867 struct socket_address *src)
868{
869 NTSTATUS status;
870 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
871 struct nbtd_interface);
872 struct wins_server *winssrv = iface->nbtsrv->winssrv;
873 struct nbt_name *name = &packet->questions[0].name;
874 struct winsdb_record *rec;
875 uint32_t modify_flags = 0;
876 uint8_t ret;
877
878 if (name->type == NBT_NAME_MASTER) {
879 goto done;
880 }
881
882 if (name->scope && strlen(name->scope) > 237) {
883 goto done;
884 }
885
886 status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
887 if (!NT_STATUS_IS_OK(status)) {
888 goto done;
889 }
890
891 if (rec->is_static) {
892 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
893 goto done;
894 }
895 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
896 return;
897 }
898
899 if (rec->state != WREPL_STATE_ACTIVE) {
900 goto done;
901 }
902
903 /*
904 * TODO: do we need to check if
905 * src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
906 * here?
907 */
908
909 /*
910 * we only allow releases from an owner - other releases are
911 * silently ignored
912 */
913 if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
914 int i;
915 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
916 DEBUGADD(4, ("Registered Addresses: \n"));
917 for (i=0; rec->addresses && rec->addresses[i]; i++) {
918 DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
919 }
920 goto done;
921 }
922
923 DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
924
925 switch (rec->type) {
926 case WREPL_TYPE_UNIQUE:
927 rec->state = WREPL_STATE_RELEASED;
928 break;
929
930 case WREPL_TYPE_GROUP:
931 rec->state = WREPL_STATE_RELEASED;
932 break;
933
934 case WREPL_TYPE_SGROUP:
935 winsdb_addr_list_remove(rec->addresses, src->addr);
936 /* TODO: do we need to take the ownership here? */
937 if (winsdb_addr_list_length(rec->addresses) == 0) {
938 rec->state = WREPL_STATE_RELEASED;
939 }
940 break;
941
942 case WREPL_TYPE_MHOMED:
943 winsdb_addr_list_remove(rec->addresses, src->addr);
944 /* TODO: do we need to take the ownership here? */
945 if (winsdb_addr_list_length(rec->addresses) == 0) {
946 rec->state = WREPL_STATE_RELEASED;
947 }
948 break;
949 }
950
951 if (rec->state == WREPL_STATE_ACTIVE) {
952 /*
953 * If the record is still active, we need to update the
954 * expire_time.
955 *
956 * if we're not the owner, we need to take the ownership.
957 */
958 rec->expire_time= time(NULL) + winssrv->config.max_renew_interval;
959 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) != 0) {
960 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
961 }
962 if (lpcfg_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
963 /*
964 * We have an option to propagate every name release,
965 * this is off by default to match windows servers
966 */
967 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
968 }
969 } else if (rec->state == WREPL_STATE_RELEASED) {
970 /*
971 * if we're not the owner, we need to take the owner ship
972 * and make the record tombstone, but expire after
973 * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
974 * like for normal tombstone records.
975 * This is to replicate the record directly to the original owner,
976 * where the record is still active
977 */
978 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
979 rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
980 } else {
981 rec->state = WREPL_STATE_TOMBSTONE;
982 rec->expire_time= time(NULL) +
983 winssrv->config.tombstone_interval +
984 winssrv->config.tombstone_timeout;
985 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
986 }
987 }
988
989 ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
990 if (ret != NBT_RCODE_OK) {
991 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
992 nbt_name_string(rec, rec->name), src->addr, ret));
993 }
994done:
995 /* we match w2k3 by always giving a positive reply to name releases. */
996 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
997}
998
999
1000/*
1001 answer a name query
1002*/
1003void nbtd_winsserver_request(struct nbt_name_socket *nbtsock,
1004 struct nbt_name_packet *packet,
1005 struct socket_address *src)
1006{
1007 struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
1008 struct nbtd_interface);
1009 struct wins_server *winssrv = iface->nbtsrv->winssrv;
1010 if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
1011 return;
1012 }
1013
1014 switch (packet->operation & NBT_OPCODE) {
1015 case NBT_OPCODE_QUERY:
1016 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1017 break;
1018
1019 case NBT_OPCODE_REGISTER:
1020 case NBT_OPCODE_REFRESH:
1021 case NBT_OPCODE_REFRESH2:
1022 case NBT_OPCODE_MULTI_HOME_REG:
1023 nbtd_winsserver_register(nbtsock, packet, src);
1024 break;
1025
1026 case NBT_OPCODE_RELEASE:
1027 nbtd_winsserver_release(nbtsock, packet, src);
1028 break;
1029 }
1030
1031}
1032
1033/*
1034 startup the WINS server, if configured
1035*/
1036NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
1037{
1038 uint32_t tmp;
1039 const char *owner;
1040
1041 if (!lpcfg_wins_support(nbtsrv->task->lp_ctx)) {
1042 nbtsrv->winssrv = NULL;
1043 return NT_STATUS_OK;
1044 }
1045
1046 nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
1047 NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
1048
1049 nbtsrv->winssrv->config.max_renew_interval = lpcfg_max_wins_ttl(nbtsrv->task->lp_ctx);
1050 nbtsrv->winssrv->config.min_renew_interval = lpcfg_min_wins_ttl(nbtsrv->task->lp_ctx);
1051 tmp = lpcfg_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1052 nbtsrv->winssrv->config.tombstone_interval = tmp;
1053 tmp = lpcfg_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1054 nbtsrv->winssrv->config.tombstone_timeout = tmp;
1055
1056 owner = lpcfg_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1057
1058 if (owner == NULL) {
1059 struct interface *ifaces;
1060 load_interfaces(nbtsrv->task, lpcfg_interfaces(nbtsrv->task->lp_ctx), &ifaces);
1061 owner = iface_n_ip(ifaces, 0);
1062 }
1063
1064 nbtsrv->winssrv->wins_db = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx,
1065 nbtsrv->task->lp_ctx,
1066 owner, WINSDB_HANDLE_CALLER_NBTD);
1067 if (!nbtsrv->winssrv->wins_db) {
1068 return NT_STATUS_INTERNAL_DB_ERROR;
1069 }
1070
1071 irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
1072
1073 return NT_STATUS_OK;
1074}
Note: See TracBrowser for help on using the repository browser.