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