s4:winsserver: reject name registrations with a scope length > 237
[ira/wip.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         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_qsort(addresses, num_addrs , sizeof(addresses[0]),
673                   src, (ldb_qsort_cmp_fn_t)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 }