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