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