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