r12618: use our primary interface address or the "winsdb:local_owner" -address
[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
32 /*
33   work out the ttl we will use given a client requested ttl
34 */
35 uint32_t wins_server_ttl(struct wins_server *winssrv, uint32_t ttl)
36 {
37         ttl = MIN(ttl, winssrv->config.max_renew_interval);
38         ttl = MAX(ttl, winssrv->config.min_renew_interval);
39         return ttl;
40 }
41
42 static enum wrepl_name_type wrepl_type(uint16_t nb_flags, struct nbt_name *name, BOOL mhomed)
43 {
44         /* this copes with the nasty hack that is the type 0x1c name */
45         if (name->type == NBT_NAME_LOGON) {
46                 return WREPL_TYPE_SGROUP;
47         }
48         if (nb_flags & NBT_NM_GROUP) {
49                 return WREPL_TYPE_GROUP;
50         }
51         if (mhomed) {
52                 return WREPL_TYPE_MHOMED;
53         }
54         return WREPL_TYPE_UNIQUE;
55 }
56
57 /*
58   register a new name with WINS
59 */
60 static uint8_t wins_register_new(struct nbt_name_socket *nbtsock, 
61                                  struct nbt_name_packet *packet, 
62                                  const struct nbt_peer_socket *src,
63                                  enum wrepl_name_type type)
64 {
65         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
66                                                        struct nbtd_interface);
67         struct wins_server *winssrv = iface->nbtsrv->winssrv;
68         struct nbt_name *name = &packet->questions[0].name;
69         uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
70         uint16_t nb_flags = packet->additional[0].rdata.netbios.addresses[0].nb_flags;
71         const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
72         struct winsdb_record rec;
73         enum wrepl_name_node node;
74
75 #define WREPL_NODE_NBT_FLAGS(nb_flags) \
76         ((nb_flags & NBT_NM_OWNER_TYPE)>>13)
77
78         node    = WREPL_NODE_NBT_FLAGS(nb_flags);
79
80         rec.name                = name;
81         rec.type                = type;
82         rec.state               = WREPL_STATE_ACTIVE;
83         rec.node                = node;
84         rec.is_static           = False;
85         rec.expire_time         = time(NULL) + ttl;
86         rec.version             = 0; /* will be allocated later */
87         rec.wins_owner          = NULL; /* will be set later */
88         rec.registered_by       = src->addr;
89         rec.addresses           = winsdb_addr_list_make(packet);
90         if (rec.addresses == NULL) return NBT_RCODE_SVR;
91
92         rec.addresses     = winsdb_addr_list_add(rec.addresses,
93                                                  address,
94                                                  winssrv->wins_db->local_owner,
95                                                  rec.expire_time);
96         if (rec.addresses == NULL) return NBT_RCODE_SVR;
97
98         DEBUG(4,("WINS: accepted registration of %s with address %s\n",
99                  nbt_name_string(packet, name), rec.addresses[0]->address));
100         
101         return winsdb_add(winssrv->wins_db, &rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
102 }
103
104
105 /*
106   update the ttl on an existing record
107 */
108 static uint8_t wins_update_ttl(struct nbt_name_socket *nbtsock, 
109                                struct nbt_name_packet *packet, 
110                                struct winsdb_record *rec,
111                                struct winsdb_addr *winsdb_addr,
112                                const struct nbt_peer_socket *src)
113 {
114         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
115                                                        struct nbtd_interface);
116         struct wins_server *winssrv = iface->nbtsrv->winssrv;
117         uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
118         const char *address = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
119         uint32_t modify_flags = 0;
120
121         rec->expire_time   = time(NULL) + ttl;
122         rec->registered_by = src->addr;
123
124         if (winsdb_addr) {
125                 winsdb_addr->wins_owner  = winssrv->wins_db->local_owner;
126                 winsdb_addr->expire_time = rec->expire_time;
127         }
128
129         if (strcmp(winssrv->wins_db->local_owner, rec->wins_owner) != 0) {
130                 modify_flags = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
131         }
132
133         DEBUG(5,("WINS: refreshed registration of %s at %s\n",
134                  nbt_name_string(packet, rec->name), address));
135         
136         return winsdb_modify(winssrv->wins_db, rec, modify_flags);
137 }
138
139 /*
140   do a sgroup merge
141 */
142 static uint8_t wins_sgroup_merge(struct nbt_name_socket *nbtsock, 
143                                  struct nbt_name_packet *packet, 
144                                  struct winsdb_record *rec,
145                                  const char *address,
146                                  const struct nbt_peer_socket *src)
147 {
148         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
149                                                        struct nbtd_interface);
150         struct wins_server *winssrv = iface->nbtsrv->winssrv;
151         uint32_t ttl = wins_server_ttl(winssrv, packet->additional[0].ttl);
152
153         rec->expire_time   = time(NULL) + ttl;
154         rec->registered_by = src->addr;
155
156         rec->addresses     = winsdb_addr_list_add(rec->addresses,
157                                                   address,
158                                                   winssrv->wins_db->local_owner,
159                                                   rec->expire_time);
160         if (rec->addresses == NULL) return NBT_RCODE_SVR;
161
162         DEBUG(5,("WINS: sgroup merge of %s at %s\n",
163                  nbt_name_string(packet, rec->name), address));
164         
165         return winsdb_modify(winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
166 }
167
168 struct wack_state {
169         struct wins_server *winssrv;
170         struct nbt_name_socket *nbtsock;
171         struct nbt_name_packet *request_packet;
172         struct winsdb_record *rec;
173         struct nbt_peer_socket src;
174         const char *reg_address;
175         enum wrepl_name_type new_type;
176         struct wins_challenge_io io;
177         NTSTATUS status;
178 };
179
180 /*
181   deny a registration request
182 */
183 static void wins_wack_deny(struct wack_state *s)
184 {
185         nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
186                                      &s->src, NBT_RCODE_ACT);
187         DEBUG(4,("WINS: denied name registration request for %s from %s:%d\n",
188                  nbt_name_string(s, s->rec->name), s->src.addr, s->src.port));
189         talloc_free(s);
190 }
191
192 /*
193   allow a registration request
194 */
195 static void wins_wack_allow(struct wack_state *s)
196 {
197         NTSTATUS status;
198         uint32_t ttl = wins_server_ttl(s->winssrv, s->request_packet->additional[0].ttl);
199         struct winsdb_record *rec = s->rec, *rec2;
200         uint32_t i,j;
201
202         status = winsdb_lookup(s->winssrv->wins_db, rec->name, s, &rec2);
203         if (!NT_STATUS_IS_OK(status) ||
204             rec2->version != rec->version ||
205             strcmp(rec2->wins_owner, rec->wins_owner) != 0) {
206                 DEBUG(1,("WINS: record %s changed during WACK - failing registration\n",
207                          nbt_name_string(s, rec->name)));
208                 wins_wack_deny(s);
209                 return;
210         }
211
212         /*
213          * if the old name owner doesn't hold the name anymore
214          * handle the request as new registration for the new name owner
215          */
216         if (!NT_STATUS_IS_OK(s->status)) {
217                 uint8_t rcode;
218
219                 winsdb_delete(s->winssrv->wins_db, rec);
220                 rcode = wins_register_new(s->nbtsock, s->request_packet, &s->src, s->new_type);
221                 if (rcode != NBT_RCODE_OK) {
222                         DEBUG(1,("WINS: record %s failed to register as new during WACK\n",
223                                  nbt_name_string(s, rec->name)));
224                         wins_wack_deny(s);
225                         return;
226                 }
227                 goto done;
228         }
229
230         rec->expire_time = time(NULL) + ttl;
231         rec->registered_by = s->src.addr;
232
233         /*
234          * now remove all addresses that're the client doesn't hold anymore
235          * and update the time stamp and owner for the ownes that are still there
236          */
237         for (i=0; rec->addresses[i]; i++) {
238                 BOOL found = False;
239                 for (j=0; j < s->io.out.num_addresses; j++) {
240                         if (strcmp(rec->addresses[i]->address, s->io.out.addresses[j]) != 0) continue;
241
242                         found = True;
243                         break;
244                 }
245                 if (found) {
246                         rec->addresses[i]->wins_owner = s->winssrv->wins_db->local_owner;
247                         rec->addresses[i]->expire_time = rec->expire_time;
248                         continue;
249                 }
250
251                 winsdb_addr_list_remove(rec->addresses, rec->addresses[i]->address);
252         }
253
254         rec->addresses = winsdb_addr_list_add(rec->addresses,
255                                               s->reg_address,
256                                               s->winssrv->wins_db->local_owner,
257                                               rec->expire_time);
258         if (rec->addresses == NULL) goto failed;
259
260         /* if we have more than one address, this becomes implicit a MHOMED record */
261         if (winsdb_addr_list_length(rec->addresses) > 1) {
262                 rec->type = WREPL_TYPE_MHOMED;
263         }
264
265         winsdb_modify(s->winssrv->wins_db, rec, WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP);
266
267         DEBUG(4,("WINS: accepted registration of %s with address %s\n",
268                  nbt_name_string(s, rec->name), s->reg_address));
269
270 done:
271         nbtd_name_registration_reply(s->nbtsock, s->request_packet, 
272                                      &s->src, NBT_RCODE_OK);
273 failed:
274         talloc_free(s);
275 }
276
277 /*
278   called when a name query to a current owner completes
279 */
280 static void wack_wins_challenge_handler(struct composite_context *c_req)
281 {
282         struct wack_state *s = talloc_get_type(c_req->async.private_data,
283                                                struct wack_state);
284         BOOL found;
285         uint32_t i;
286
287         s->status = wins_challenge_recv(c_req, s, &s->io);
288
289         /*
290          * if the owner denies it holds the name, then allow
291          * the registration
292          */
293         if (!NT_STATUS_IS_OK(s->status)) {
294                 wins_wack_allow(s);
295                 return;
296         }
297
298         if (s->new_type == WREPL_TYPE_GROUP || s->new_type == WREPL_TYPE_SGROUP) {
299                 DEBUG(1,("WINS: record %s failed to register as group type(%u) during WACK, it's still type(%u)\n",
300                          nbt_name_string(s, s->rec->name), s->new_type, s->rec->type));
301                 wins_wack_deny(s);
302                 return;
303         }
304
305         /*
306          * if the owner still wants the name and doesn't reply
307          * with the address trying to be registered, then deny
308          * the registration
309          */
310         found = False;
311         for (i=0; i < s->io.out.num_addresses; i++) {
312                 if (strcmp(s->reg_address, s->io.out.addresses[i]) != 0) continue;
313
314                 found = True;
315                 break;
316         }
317         if (!found) {
318                 wins_wack_deny(s);
319                 return;
320         }
321
322         wins_wack_allow(s);
323         return;
324 }
325
326
327 /*
328   a client has asked to register a unique name that someone else owns. We
329   need to ask each of the current owners if they still want it. If they do
330   then reject the registration, otherwise allow it
331 */
332 static void wins_register_wack(struct nbt_name_socket *nbtsock, 
333                                struct nbt_name_packet *packet, 
334                                struct winsdb_record *rec,
335                                const struct nbt_peer_socket *src,
336                                enum wrepl_name_type new_type)
337 {
338         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
339                                                        struct nbtd_interface);
340         struct wins_server *winssrv = iface->nbtsrv->winssrv;
341         struct wack_state *s;
342         struct composite_context *c_req;
343         uint32_t ttl;
344
345         s = talloc_zero(nbtsock, struct wack_state);
346         if (s == NULL) goto failed;
347
348         /* package up the state variables for this wack request */
349         s->winssrv              = winssrv;
350         s->nbtsock              = nbtsock;
351         s->request_packet       = talloc_steal(s, packet);
352         s->rec                  = talloc_steal(s, rec);
353         s->reg_address          = packet->additional[0].rdata.netbios.addresses[0].ipaddr;
354         s->new_type             = new_type;
355         s->src.port             = src->port;
356         s->src.addr             = talloc_strdup(s, src->addr);
357         if (s->src.addr == 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                                      const struct nbt_peer_socket *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                                   const struct nbt_peer_socket *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; /* TODO: ... */
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                 goto notfound;
587         }
588
589         /*
590          * for group's we always reply with
591          * 255.255.255.255 as address, even if
592          * the record is released or tombstoned
593          */
594         if (rec->type == WREPL_TYPE_GROUP) {
595                 addresses = talloc_array(packet, const char *, 2);
596                 if (addresses == NULL) {
597                         nbtd_negative_name_query_reply(nbtsock, packet, src);
598                         return;
599                 }
600                 addresses[0] = "255.255.255.255";
601                 addresses[1] = NULL;
602                 goto found;
603         }
604
605         if (rec->state != WREPL_STATE_ACTIVE) {
606                 goto notfound;
607         }
608
609         addresses = winsdb_addr_string_list(packet, rec->addresses);
610         if (!addresses) {
611                 goto notfound;
612         }
613
614         /* 
615          * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
616          * first 0x1B address as first address
617          */
618         if (addresses_1b && addresses_1b[0]) {
619                 const char **addresses_1c = addresses;
620                 uint32_t i;
621
622                 addresses = str_list_add(NULL, addresses_1b[0]);
623                 if (!addresses) {
624                         goto notfound;
625                 }
626                 talloc_steal(packet, addresses);
627
628                 for (i=0; addresses_1c[i]; i++) {
629                         if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
630
631                         addresses = str_list_add(addresses, addresses_1c[i]);
632                         if (!addresses) {
633                                 goto notfound;
634                         }
635                 }
636         }
637
638 found:
639         nbtd_name_query_reply(nbtsock, packet, src, name, 
640                               0, nb_flags, addresses);
641         return;
642
643 notfound:
644         nbtd_negative_name_query_reply(nbtsock, packet, src);
645 }
646
647 /*
648   release a name
649 */
650 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
651                                     struct nbt_name_packet *packet, 
652                                     const struct nbt_peer_socket *src)
653 {
654         NTSTATUS status;
655         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
656                                                        struct nbtd_interface);
657         struct wins_server *winssrv = iface->nbtsrv->winssrv;
658         struct nbt_name *name = &packet->questions[0].name;
659         struct winsdb_record *rec;
660         uint32_t modify_flags = 0;
661         uint8_t ret;
662
663         if (name->type == NBT_NAME_MASTER) {
664                 goto done;
665         }
666
667         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
668         if (!NT_STATUS_IS_OK(status)) {
669                 goto done;
670         }
671
672         if (rec->is_static) {
673                 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
674                         goto done;
675                 }
676                 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
677                 return;
678         }
679
680         if (rec->state != WREPL_STATE_ACTIVE) {
681                 goto done;
682         }
683
684         /* 
685          * TODO: do we need to check if
686          *       src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
687          *       here?
688          */
689
690         /* 
691          * we only allow releases from an owner - other releases are
692          * silently ignored
693          */
694         if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
695                 goto done;
696         }
697
698         DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
699
700         switch (rec->type) {
701         case WREPL_TYPE_UNIQUE:
702                 rec->state = WREPL_STATE_RELEASED;
703                 break;
704
705         case WREPL_TYPE_GROUP:
706                 rec->state = WREPL_STATE_RELEASED;
707                 break;
708
709         case WREPL_TYPE_SGROUP:
710                 winsdb_addr_list_remove(rec->addresses, src->addr);
711                 /* TODO: do we need to take the ownership here? */
712                 if (winsdb_addr_list_length(rec->addresses) == 0) {
713                         rec->state = WREPL_STATE_RELEASED;
714                 }
715                 break;
716
717         case WREPL_TYPE_MHOMED:
718                 winsdb_addr_list_remove(rec->addresses, src->addr);
719                 /* TODO: do we need to take the ownership here? */
720                 if (winsdb_addr_list_length(rec->addresses) == 0) {
721                         rec->state = WREPL_STATE_RELEASED;
722                 }
723                 break;
724         }
725
726         if (rec->state == WREPL_STATE_RELEASED) {
727                 rec->expire_time = time(NULL) + winssrv->config.tombstone_interval;
728         }
729
730         ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
731         if (ret != NBT_RCODE_OK) {
732                 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
733                         nbt_name_string(rec, rec->name), src->addr, ret));
734         }
735 done:
736         /* we match w2k3 by always giving a positive reply to name releases. */
737         nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
738 }
739
740
741 /*
742   answer a name query
743 */
744 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, 
745                              struct nbt_name_packet *packet, 
746                              const struct nbt_peer_socket *src)
747 {
748         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
749                                                        struct nbtd_interface);
750         struct wins_server *winssrv = iface->nbtsrv->winssrv;
751         if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
752                 return;
753         }
754
755         switch (packet->operation & NBT_OPCODE) {
756         case NBT_OPCODE_QUERY:
757                 nbtd_winsserver_query(nbtsock, packet, src);
758                 break;
759
760         case NBT_OPCODE_REGISTER:
761         case NBT_OPCODE_REFRESH:
762         case NBT_OPCODE_REFRESH2:
763         case NBT_OPCODE_MULTI_HOME_REG:
764                 nbtd_winsserver_register(nbtsock, packet, src);
765                 break;
766
767         case NBT_OPCODE_RELEASE:
768                 nbtd_winsserver_release(nbtsock, packet, src);
769                 break;
770         }
771
772 }
773
774 /*
775   startup the WINS server, if configured
776 */
777 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
778 {
779         uint32_t tombstone_interval;
780
781         if (!lp_wins_support()) {
782                 nbtsrv->winssrv = NULL;
783                 return NT_STATUS_OK;
784         }
785
786         nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
787         NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
788
789         nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
790         nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
791         tombstone_interval = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
792         nbtsrv->winssrv->config.tombstone_interval = tombstone_interval;
793
794         nbtsrv->winssrv->wins_db     = winsdb_connect(nbtsrv->winssrv);
795         if (!nbtsrv->winssrv->wins_db) {
796                 return NT_STATUS_INTERNAL_DB_ERROR;
797         }
798
799         irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
800
801         return NT_STATUS_OK;
802 }