More spelling fixes across source4/
[samba.git] / source4 / nbt_server / wins / winsserver.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    core wins server handling
5
6    Copyright (C) Andrew Tridgell        2005
7    Copyright (C) Stefan Metzmacher      2005
8       
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "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 the client doesn't hold anymore
285          * and update the time stamp and owner for the ones 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         if (name->scope && strlen(name->scope) > 237) {
500                 rcode = NBT_RCODE_SVR;
501                 goto done;
502         }
503
504         duplicate_packet = wins_check_wack_queue(iface, packet, src);
505         if (duplicate_packet) {
506                 /* just ignore the packet */
507                 DEBUG(5,("Ignoring duplicate packet while WACK is pending from %s:%d\n",
508                          src->addr, src->port));
509                 return;
510         }
511
512         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
513         if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
514                 rcode = wins_register_new(nbtsock, packet, src, new_type);
515                 goto done;
516         } else if (!NT_STATUS_IS_OK(status)) {
517                 rcode = NBT_RCODE_SVR;
518                 goto done;
519         } else if (rec->is_static) {
520                 if (rec->type == WREPL_TYPE_GROUP || rec->type == WREPL_TYPE_SGROUP) {
521                         rcode = NBT_RCODE_OK;
522                         goto done;
523                 }
524                 rcode = NBT_RCODE_ACT;
525                 goto done;
526         }
527
528         if (rec->type == WREPL_TYPE_GROUP) {
529                 if (new_type != WREPL_TYPE_GROUP) {
530                         DEBUG(2,("WINS: Attempt to register name %s as non normal group(%u)"
531                                  " while a normal group is already there\n",
532                                  nbt_name_string(packet, name), new_type));
533                         rcode = NBT_RCODE_ACT;
534                         goto done;
535                 }
536
537                 if (rec->state == WREPL_STATE_ACTIVE) {
538                         /* TODO: is this correct? */
539                         rcode = wins_update_ttl(nbtsock, packet, rec, NULL, src);
540                         goto done;
541                 }
542
543                 /* TODO: is this correct? */
544                 winsdb_delete(winssrv->wins_db, rec);
545                 rcode = wins_register_new(nbtsock, packet, src, new_type);
546                 goto done;
547         }
548
549         if (rec->state != WREPL_STATE_ACTIVE) {
550                 winsdb_delete(winssrv->wins_db, rec);
551                 rcode = wins_register_new(nbtsock, packet, src, new_type);
552                 goto done;
553         }
554
555         switch (rec->type) {
556         case WREPL_TYPE_UNIQUE:
557         case WREPL_TYPE_MHOMED:
558                 /* 
559                  * if its an active unique name, and the registration is for a group, then
560                  * see if the unique name owner still wants the name
561                  * TODO: is this correct?
562                  */
563                 if (new_type == WREPL_TYPE_GROUP || new_type == WREPL_TYPE_GROUP) {
564                         wins_register_wack(nbtsock, packet, rec, src, new_type);
565                         return;
566                 }
567
568                 /* 
569                  * if the registration is for an address that is currently active, then 
570                  * just update the expiry time of the record and the address
571                  */
572                 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
573                 if (winsdb_addr) {
574                         rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
575                         goto done;
576                 }
577
578                 /*
579                  * we have to do a WACK to see if the current owner is willing
580                  * to give up its claim
581                  */
582                 wins_register_wack(nbtsock, packet, rec, src, new_type);
583                 return;
584
585         case WREPL_TYPE_GROUP:
586                 /* this should not be reached as normal groups are handled above */
587                 DEBUG(0,("BUG at %s\n",__location__));
588                 rcode = NBT_RCODE_ACT;
589                 goto done;
590
591         case WREPL_TYPE_SGROUP:
592                 /* if the new record isn't also a special group, refuse the registration */ 
593                 if (new_type != WREPL_TYPE_SGROUP) {
594                         DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
595                                  " while a special group is already there\n",
596                                  nbt_name_string(packet, name), new_type));
597                         rcode = NBT_RCODE_ACT;
598                         goto done;
599                 }
600
601                 /* 
602                  * if the registration is for an address that is currently active, then 
603                  * just update the expiry time of the record and the address
604                  */
605                 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
606                 if (winsdb_addr) {
607                         rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
608                         goto done;
609                 }
610
611                 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
612                 goto done;
613         }
614
615 done:
616         nbtd_name_registration_reply(nbtsock, packet, src, rcode);
617 }
618
619 static uint32_t ipv4_match_bits(struct in_addr ip1, struct in_addr ip2)
620 {
621         uint32_t i, j, match=0;
622         uint8_t *p1, *p2;
623
624         p1 = (uint8_t *)&ip1.s_addr;
625         p2 = (uint8_t *)&ip2.s_addr;
626
627         for (i=0; i<4; i++) {
628                 if (p1[i] != p2[i]) break;
629                 match += 8;
630         }
631
632         if (i==4) return match;
633
634         for (j=0; j<8; j++) {
635                 if ((p1[i] & (1<<(7-j))) != (p2[i] & (1<<(7-j))))
636                         break;
637                 match++;
638         }
639
640         return match;
641 }
642
643 static int nbtd_wins_randomize1Clist_sort(void *p1,/* (const char **) */
644                                           void *p2,/* (const char **) */
645                                           struct socket_address *src)
646 {
647         const char *a1 = (const char *)*(const char **)p1;
648         const char *a2 = (const char *)*(const char **)p2;
649         uint32_t match_bits1;
650         uint32_t match_bits2;
651
652         match_bits1 = ipv4_match_bits(interpret_addr2(a1), interpret_addr2(src->addr));
653         match_bits2 = ipv4_match_bits(interpret_addr2(a2), interpret_addr2(src->addr));
654
655         return match_bits2 - match_bits1;
656 }
657
658 static void nbtd_wins_randomize1Clist(struct loadparm_context *lp_ctx,
659                                       const char **addresses, struct socket_address *src)
660 {
661         const char *mask;
662         const char *tmp;
663         uint32_t num_addrs;
664         uint32_t idx, sidx;
665         int r;
666
667         for (num_addrs=0; addresses[num_addrs]; num_addrs++) { /* noop */ }
668
669         if (num_addrs <= 1) return; /* nothing to do */
670
671         /* first sort the addresses depending on the matching to the client */
672         LDB_TYPESAFE_QSORT(addresses, num_addrs, src, nbtd_wins_randomize1Clist_sort);
673
674         mask = lp_parm_string(lp_ctx, NULL, "nbtd", "wins_randomize1Clist_mask");
675         if (!mask) {
676                 mask = "255.255.255.0";
677         }
678
679         /* 
680          * choose a random address to be the first in the response to the client,
681          * preferr the addresses inside the nbtd:wins_randomize1Clist_mask netmask
682          */
683         r = random();
684         idx = sidx = r % num_addrs;
685
686         while (1) {
687                 bool same;
688
689                 /* if the current one is in the same subnet, use it */
690                 same = iface_same_net(addresses[idx], src->addr, mask);
691                 if (same) {
692                         sidx = idx;
693                         break;
694                 }
695
696                 /* we need to check for idx == 0, after checking for the same net */
697                 if (idx == 0) break;
698                 /* 
699                  * if we haven't found an address in the same subnet, search in ones
700                  * which match the client more
701                  *
702                  * some notes:
703                  *
704                  * it's not "idx = idx % r" but "idx = r % idx"
705                  * because in "a % b" b is the allowed range
706                  * and b-1 is the maximum possible result, so it must be decreasing
707                  * and the above idx == 0 check breaks the while(1) loop.
708                  */
709                 idx = r % idx;
710         }
711
712         /* note sidx == 0 is also valid here ... */
713         tmp             = addresses[0];
714         addresses[0]    = addresses[sidx];
715         addresses[sidx] = tmp;
716 }
717
718 /*
719   query a name
720 */
721 static void nbtd_winsserver_query(struct loadparm_context *lp_ctx,
722                                   struct nbt_name_socket *nbtsock, 
723                                   struct nbt_name_packet *packet, 
724                                   struct socket_address *src)
725 {
726         NTSTATUS status;
727         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
728                                                        struct nbtd_interface);
729         struct wins_server *winssrv = iface->nbtsrv->winssrv;
730         struct nbt_name *name = &packet->questions[0].name;
731         struct winsdb_record *rec;
732         struct winsdb_record *rec_1b = NULL;
733         const char **addresses;
734         const char **addresses_1b = NULL;
735         uint16_t nb_flags = 0;
736
737         if (name->type == NBT_NAME_MASTER) {
738                 goto notfound;
739         }
740
741         /*
742          * w2k3 returns the first address of the 0x1B record as first address
743          * to a 0x1C query
744          *
745          * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
746          *
747          * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Prepend1BTo1CQueries
748          * Typ: Daten REG_DWORD
749          * Value: 0 = deactivated, 1 = activated
750          */
751         if (name->type == NBT_NAME_LOGON && 
752             lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_prepend1Bto1Cqueries", true)) {
753                 struct nbt_name name_1b;
754
755                 name_1b = *name;
756                 name_1b.type = NBT_NAME_PDC;
757
758                 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
759                 if (NT_STATUS_IS_OK(status)) {
760                         addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
761                 }
762         }
763
764         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
765         if (!NT_STATUS_IS_OK(status)) {
766                 if (!lp_wins_dns_proxy(lp_ctx)) {
767                         goto notfound;
768                 }
769
770                 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
771                         goto notfound;
772                 }
773
774                 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
775                 return;
776         }
777
778         /*
779          * for group's we always reply with
780          * 255.255.255.255 as address, even if
781          * the record is released or tombstoned
782          */
783         if (rec->type == WREPL_TYPE_GROUP) {
784                 addresses = str_list_add(NULL, "255.255.255.255");
785                 talloc_steal(packet, addresses);
786                 if (!addresses) {
787                         goto notfound;
788                 }
789                 nb_flags |= NBT_NM_GROUP;
790                 goto found;
791         }
792
793         if (rec->state != WREPL_STATE_ACTIVE) {
794                 goto notfound;
795         }
796
797         addresses = winsdb_addr_string_list(packet, rec->addresses);
798         if (!addresses) {
799                 goto notfound;
800         }
801
802         /* 
803          * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
804          * first 0x1B address as first address
805          */
806         if (addresses_1b && addresses_1b[0]) {
807                 const char **addresses_1c = addresses;
808                 uint32_t i;
809                 uint32_t num_addrs;
810
811                 addresses = str_list_add(NULL, addresses_1b[0]);
812                 if (!addresses) {
813                         goto notfound;
814                 }
815                 talloc_steal(packet, addresses);
816                 num_addrs = 1;
817
818                 for (i=0; addresses_1c[i]; i++) {
819                         if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
820
821                         /*
822                          * stop when we already have 25 addresses
823                          */
824                         if (num_addrs >= 25) break;
825
826                         num_addrs++;                    
827                         addresses = str_list_add(addresses, addresses_1c[i]);
828                         if (!addresses) {
829                                 goto notfound;
830                         }
831                 }
832         }
833
834         if (rec->type == WREPL_TYPE_SGROUP) {
835                 nb_flags |= NBT_NM_GROUP;
836         } else {
837                 nb_flags |= (rec->node <<13);
838         }
839
840         /*
841          * since Windows 2000 Service Pack 2 there's on option to trigger this behavior:
842          *
843          * HKEY_LOCAL_MACHINE\System\CurrentControlset\Services\WINS\Parameters\Randomize1CList
844          * Typ: Daten REG_DWORD
845          * Value: 0 = deactivated, 1 = activated
846          */
847         if (name->type == NBT_NAME_LOGON && 
848             lp_parm_bool(lp_ctx, NULL, "nbtd", "wins_randomize1Clist", false)) {
849                 nbtd_wins_randomize1Clist(lp_ctx, addresses, src);
850         }
851
852 found:
853         nbtd_name_query_reply(nbtsock, packet, src, name, 
854                               0, nb_flags, addresses);
855         return;
856
857 notfound:
858         nbtd_negative_name_query_reply(nbtsock, packet, src);
859 }
860
861 /*
862   release a name
863 */
864 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
865                                     struct nbt_name_packet *packet, 
866                                     struct socket_address *src)
867 {
868         NTSTATUS status;
869         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
870                                                        struct nbtd_interface);
871         struct wins_server *winssrv = iface->nbtsrv->winssrv;
872         struct nbt_name *name = &packet->questions[0].name;
873         struct winsdb_record *rec;
874         uint32_t modify_flags = 0;
875         uint8_t ret;
876
877         if (name->type == NBT_NAME_MASTER) {
878                 goto done;
879         }
880
881         if (name->scope && strlen(name->scope) > 237) {
882                 goto done;
883         }
884
885         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
886         if (!NT_STATUS_IS_OK(status)) {
887                 goto done;
888         }
889
890         if (rec->is_static) {
891                 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
892                         goto done;
893                 }
894                 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
895                 return;
896         }
897
898         if (rec->state != WREPL_STATE_ACTIVE) {
899                 goto done;
900         }
901
902         /* 
903          * TODO: do we need to check if
904          *       src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
905          *       here?
906          */
907
908         /* 
909          * we only allow releases from an owner - other releases are
910          * silently ignored
911          */
912         if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
913                 int i;
914                 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
915                 DEBUGADD(4, ("Registered Addresses: \n"));
916                 for (i=0; rec->addresses && rec->addresses[i]; i++) {
917                         DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
918                 }
919                 goto done;
920         }
921
922         DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
923
924         switch (rec->type) {
925         case WREPL_TYPE_UNIQUE:
926                 rec->state = WREPL_STATE_RELEASED;
927                 break;
928
929         case WREPL_TYPE_GROUP:
930                 rec->state = WREPL_STATE_RELEASED;
931                 break;
932
933         case WREPL_TYPE_SGROUP:
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         case WREPL_TYPE_MHOMED:
942                 winsdb_addr_list_remove(rec->addresses, src->addr);
943                 /* TODO: do we need to take the ownership here? */
944                 if (winsdb_addr_list_length(rec->addresses) == 0) {
945                         rec->state = WREPL_STATE_RELEASED;
946                 }
947                 break;
948         }
949
950         if (rec->state == WREPL_STATE_ACTIVE) {
951                 /*
952                  * If the record is still active, we need to update the
953                  * expire_time.
954                  *
955                  * if we're not the owner, we need to take the ownership.
956                  */
957                 rec->expire_time= time(NULL) + winssrv->config.max_renew_interval;
958                 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) != 0) {
959                         modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
960                 }
961                 if (lp_parm_bool(iface->nbtsrv->task->lp_ctx, NULL, "wreplsrv", "propagate name releases", false)) {
962                         /*
963                          * We have an option to propagate every name release,
964                          * this is off by default to match windows servers
965                          */
966                         modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
967                 }
968         } else if (rec->state == WREPL_STATE_RELEASED) {
969                 /*
970                  * if we're not the owner, we need to take the owner ship
971                  * and make the record tombstone, but expire after
972                  * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
973                  * like for normal tombstone records.
974                  * This is to replicate the record directly to the original owner,
975                  * where the record is still active
976                  */ 
977                 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
978                         rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
979                 } else {
980                         rec->state      = WREPL_STATE_TOMBSTONE;
981                         rec->expire_time= time(NULL) + 
982                                           winssrv->config.tombstone_interval +
983                                           winssrv->config.tombstone_timeout;
984                         modify_flags    = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
985                 }
986         }
987
988         ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
989         if (ret != NBT_RCODE_OK) {
990                 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
991                         nbt_name_string(rec, rec->name), src->addr, ret));
992         }
993 done:
994         /* we match w2k3 by always giving a positive reply to name releases. */
995         nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
996 }
997
998
999 /*
1000   answer a name query
1001 */
1002 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, 
1003                              struct nbt_name_packet *packet, 
1004                              struct socket_address *src)
1005 {
1006         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private_data,
1007                                                        struct nbtd_interface);
1008         struct wins_server *winssrv = iface->nbtsrv->winssrv;
1009         if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
1010                 return;
1011         }
1012
1013         switch (packet->operation & NBT_OPCODE) {
1014         case NBT_OPCODE_QUERY:
1015                 nbtd_winsserver_query(iface->nbtsrv->task->lp_ctx, nbtsock, packet, src);
1016                 break;
1017
1018         case NBT_OPCODE_REGISTER:
1019         case NBT_OPCODE_REFRESH:
1020         case NBT_OPCODE_REFRESH2:
1021         case NBT_OPCODE_MULTI_HOME_REG:
1022                 nbtd_winsserver_register(nbtsock, packet, src);
1023                 break;
1024
1025         case NBT_OPCODE_RELEASE:
1026                 nbtd_winsserver_release(nbtsock, packet, src);
1027                 break;
1028         }
1029
1030 }
1031
1032 /*
1033   startup the WINS server, if configured
1034 */
1035 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
1036 {
1037         uint32_t tmp;
1038         const char *owner;
1039
1040         if (!lp_wins_support(nbtsrv->task->lp_ctx)) {
1041                 nbtsrv->winssrv = NULL;
1042                 return NT_STATUS_OK;
1043         }
1044
1045         nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
1046         NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
1047
1048         nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl(nbtsrv->task->lp_ctx);
1049         nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl(nbtsrv->task->lp_ctx);
1050         tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv", "tombstone_interval", 6*24*60*60);
1051         nbtsrv->winssrv->config.tombstone_interval = tmp;
1052         tmp = lp_parm_int(nbtsrv->task->lp_ctx, NULL, "wreplsrv"," tombstone_timeout", 1*24*60*60);
1053         nbtsrv->winssrv->config.tombstone_timeout = tmp;
1054
1055         owner = lp_parm_string(nbtsrv->task->lp_ctx, NULL, "winsdb", "local_owner");
1056
1057         if (owner == NULL) {
1058                 struct interface *ifaces;
1059                 load_interfaces(nbtsrv->task, lp_interfaces(nbtsrv->task->lp_ctx), &ifaces);
1060                 owner = iface_n_ip(ifaces, 0);
1061         }
1062
1063         nbtsrv->winssrv->wins_db     = winsdb_connect(nbtsrv->winssrv, nbtsrv->task->event_ctx, 
1064                                                       nbtsrv->task->lp_ctx,
1065                                                       owner, WINSDB_HANDLE_CALLER_NBTD);
1066         if (!nbtsrv->winssrv->wins_db) {
1067                 return NT_STATUS_INTERNAL_DB_ERROR;
1068         }
1069
1070         irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
1071
1072         return NT_STATUS_OK;
1073 }