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