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