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