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