r13060: - return only active addresses in name query responses
[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                  */
496                 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
497                 if (winsdb_addr) {
498                         rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
499                         goto done;
500                 }
501
502                 /*
503                  * we have to do a WACK to see if the current owner is willing
504                  * to give up its claim
505                  */
506                 wins_register_wack(nbtsock, packet, rec, src, new_type);
507                 return;
508
509         case WREPL_TYPE_GROUP:
510                 /* this should not be reached as normal groups are handled above */
511                 DEBUG(0,("BUG at %s\n",__location__));
512                 rcode = NBT_RCODE_ACT;
513                 goto done;
514
515         case WREPL_TYPE_SGROUP:
516                 /* if the new record isn't also a special group, refuse the registration */ 
517                 if (new_type != WREPL_TYPE_SGROUP) {
518                         DEBUG(2,("WINS: Attempt to register name %s as non special group(%u)"
519                                  " while a special group is already there\n",
520                                  nbt_name_string(packet, name), new_type));
521                         rcode = NBT_RCODE_ACT;
522                         goto done;
523                 }
524
525                 /* 
526                  * if the registration is for an address that is currently active, then 
527                  * just update the expiry time of the record and the address
528                  */
529                 winsdb_addr = winsdb_addr_list_check(rec->addresses, address);
530                 if (winsdb_addr) {
531                         rcode = wins_update_ttl(nbtsock, packet, rec, winsdb_addr, src);
532                         goto done;
533                 }
534
535                 rcode = wins_sgroup_merge(nbtsock, packet, rec, address, src);
536                 goto done;
537         }
538
539 done:
540         nbtd_name_registration_reply(nbtsock, packet, src, rcode);
541 }
542
543 /*
544   query a name
545 */
546 static void nbtd_winsserver_query(struct nbt_name_socket *nbtsock, 
547                                   struct nbt_name_packet *packet, 
548                                   struct socket_address *src)
549 {
550         NTSTATUS status;
551         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
552                                                        struct nbtd_interface);
553         struct wins_server *winssrv = iface->nbtsrv->winssrv;
554         struct nbt_name *name = &packet->questions[0].name;
555         struct winsdb_record *rec;
556         struct winsdb_record *rec_1b = NULL;
557         const char **addresses;
558         const char **addresses_1b = NULL;
559         uint16_t nb_flags = 0;
560
561         if (name->type == NBT_NAME_MASTER) {
562                 goto notfound;
563         }
564
565         /*
566          * w2k3 returns the first address of the 0x1B record as first address
567          * to a 0x1C query
568          */
569         if (name->type == NBT_NAME_LOGON) {
570                 struct nbt_name name_1b;
571
572                 name_1b = *name;
573                 name_1b.type = NBT_NAME_PDC;
574
575                 status = winsdb_lookup(winssrv->wins_db, &name_1b, packet, &rec_1b);
576                 if (NT_STATUS_IS_OK(status)) {
577                         addresses_1b = winsdb_addr_string_list(packet, rec_1b->addresses);
578                 }
579         }
580
581         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
582         if (!NT_STATUS_IS_OK(status)) {
583                 if (!lp_wins_dns_proxy()) {
584                         goto notfound;
585                 }
586
587                 if (name->type != NBT_NAME_CLIENT && name->type != NBT_NAME_SERVER) {
588                         goto notfound;
589                 }
590
591                 nbtd_wins_dns_proxy_query(nbtsock, packet, src);
592                 return;
593         }
594
595         /*
596          * for group's we always reply with
597          * 255.255.255.255 as address, even if
598          * the record is released or tombstoned
599          */
600         if (rec->type == WREPL_TYPE_GROUP) {
601                 addresses = str_list_add(NULL, "255.255.255.255");
602                 talloc_steal(packet, addresses);
603                 if (!addresses) {
604                         goto notfound;
605                 }
606                 nb_flags |= NBT_NM_GROUP;
607                 goto found;
608         }
609
610         if (rec->state != WREPL_STATE_ACTIVE) {
611                 goto notfound;
612         }
613
614         addresses = winsdb_addr_string_list(packet, rec->addresses);
615         if (!addresses) {
616                 goto notfound;
617         }
618
619         /* 
620          * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
621          * first 0x1B address as first address
622          */
623         if (addresses_1b && addresses_1b[0]) {
624                 const char **addresses_1c = addresses;
625                 uint32_t i;
626
627                 addresses = str_list_add(NULL, addresses_1b[0]);
628                 if (!addresses) {
629                         goto notfound;
630                 }
631                 talloc_steal(packet, addresses);
632
633                 for (i=0; addresses_1c[i]; i++) {
634                         if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
635
636                         addresses = str_list_add(addresses, addresses_1c[i]);
637                         if (!addresses) {
638                                 goto notfound;
639                         }
640                 }
641         }
642
643         if (rec->type == WREPL_TYPE_SGROUP) {
644                 nb_flags |= NBT_NM_GROUP;
645         } else {
646                 nb_flags |= (rec->node <<13);           
647         }
648
649 found:
650         nbtd_name_query_reply(nbtsock, packet, src, name, 
651                               0, nb_flags, addresses);
652         return;
653
654 notfound:
655         nbtd_negative_name_query_reply(nbtsock, packet, src);
656 }
657
658 /*
659   release a name
660 */
661 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
662                                     struct nbt_name_packet *packet, 
663                                     struct socket_address *src)
664 {
665         NTSTATUS status;
666         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
667                                                        struct nbtd_interface);
668         struct wins_server *winssrv = iface->nbtsrv->winssrv;
669         struct nbt_name *name = &packet->questions[0].name;
670         struct winsdb_record *rec;
671         uint32_t modify_flags = 0;
672         uint8_t ret;
673
674         if (name->type == NBT_NAME_MASTER) {
675                 goto done;
676         }
677
678         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
679         if (!NT_STATUS_IS_OK(status)) {
680                 goto done;
681         }
682
683         if (rec->is_static) {
684                 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
685                         goto done;
686                 }
687                 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
688                 return;
689         }
690
691         if (rec->state != WREPL_STATE_ACTIVE) {
692                 goto done;
693         }
694
695         /* 
696          * TODO: do we need to check if
697          *       src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
698          *       here?
699          */
700
701         /* 
702          * we only allow releases from an owner - other releases are
703          * silently ignored
704          */
705         if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
706                 int i;
707                 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
708                 DEBUGADD(4, ("Registered Addressss: \n"));
709                 for (i=0; rec->addresses && rec->addresses[i]; i++) {
710                         DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
711                 }
712                 goto done;
713         }
714
715         DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
716
717         switch (rec->type) {
718         case WREPL_TYPE_UNIQUE:
719                 rec->state = WREPL_STATE_RELEASED;
720                 break;
721
722         case WREPL_TYPE_GROUP:
723                 rec->state = WREPL_STATE_RELEASED;
724                 break;
725
726         case WREPL_TYPE_SGROUP:
727                 winsdb_addr_list_remove(rec->addresses, src->addr);
728                 /* TODO: do we need to take the ownership here? */
729                 if (winsdb_addr_list_length(rec->addresses) == 0) {
730                         rec->state = WREPL_STATE_RELEASED;
731                 }
732                 break;
733
734         case WREPL_TYPE_MHOMED:
735                 winsdb_addr_list_remove(rec->addresses, src->addr);
736                 /* TODO: do we need to take the ownership here? */
737                 if (winsdb_addr_list_length(rec->addresses) == 0) {
738                         rec->state = WREPL_STATE_RELEASED;
739                 }
740                 break;
741         }
742
743         if (rec->state == WREPL_STATE_RELEASED) {
744                 /*
745                  * if we're not the owner, we need to take the owner ship
746                  * and make the record tombstone, but expire after
747                  * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
748                  * like for normal tombstone records.
749                  * This is to replicate the record directly to the original owner,
750                  * where the record is still active
751                  */ 
752                 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
753                         rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
754                 } else {
755                         rec->state      = WREPL_STATE_TOMBSTONE;
756                         rec->expire_time= time(NULL) + 
757                                           winssrv->config.tombstone_interval +
758                                           winssrv->config.tombstone_timeout;
759                         modify_flags    = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
760                 }
761         }
762
763         ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
764         if (ret != NBT_RCODE_OK) {
765                 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
766                         nbt_name_string(rec, rec->name), src->addr, ret));
767         }
768 done:
769         /* we match w2k3 by always giving a positive reply to name releases. */
770         nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
771 }
772
773
774 /*
775   answer a name query
776 */
777 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, 
778                              struct nbt_name_packet *packet, 
779                              struct socket_address *src)
780 {
781         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
782                                                        struct nbtd_interface);
783         struct wins_server *winssrv = iface->nbtsrv->winssrv;
784         if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
785                 return;
786         }
787
788         switch (packet->operation & NBT_OPCODE) {
789         case NBT_OPCODE_QUERY:
790                 nbtd_winsserver_query(nbtsock, packet, src);
791                 break;
792
793         case NBT_OPCODE_REGISTER:
794         case NBT_OPCODE_REFRESH:
795         case NBT_OPCODE_REFRESH2:
796         case NBT_OPCODE_MULTI_HOME_REG:
797                 nbtd_winsserver_register(nbtsock, packet, src);
798                 break;
799
800         case NBT_OPCODE_RELEASE:
801                 nbtd_winsserver_release(nbtsock, packet, src);
802                 break;
803         }
804
805 }
806
807 /*
808   startup the WINS server, if configured
809 */
810 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
811 {
812         uint32_t tmp;
813
814         if (!lp_wins_support()) {
815                 nbtsrv->winssrv = NULL;
816                 return NT_STATUS_OK;
817         }
818
819         nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
820         NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
821
822         nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
823         nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
824         tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
825         nbtsrv->winssrv->config.tombstone_interval = tmp;
826         tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
827         nbtsrv->winssrv->config.tombstone_timeout = tmp;
828
829         nbtsrv->winssrv->wins_db     = winsdb_connect(nbtsrv->winssrv, WINSDB_HANDLE_CALLER_NBTD);
830         if (!nbtsrv->winssrv->wins_db) {
831                 return NT_STATUS_INTERNAL_DB_ERROR;
832         }
833
834         irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
835
836         return NT_STATUS_OK;
837 }