r12804: This patch reworks the Samba4 sockets layer to use a socket_address
[obnox/samba/samba-obnox.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; /* 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                 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                 goto found;
610         }
611
612         if (rec->state != WREPL_STATE_ACTIVE) {
613                 goto notfound;
614         }
615
616         addresses = winsdb_addr_string_list(packet, rec->addresses);
617         if (!addresses) {
618                 goto notfound;
619         }
620
621         /* 
622          * if addresses_1b isn't NULL, we have a 0x1C query and need to return the
623          * first 0x1B address as first address
624          */
625         if (addresses_1b && addresses_1b[0]) {
626                 const char **addresses_1c = addresses;
627                 uint32_t i;
628
629                 addresses = str_list_add(NULL, addresses_1b[0]);
630                 if (!addresses) {
631                         goto notfound;
632                 }
633                 talloc_steal(packet, addresses);
634
635                 for (i=0; addresses_1c[i]; i++) {
636                         if (strcmp(addresses_1b[0], addresses_1c[i]) == 0) continue;
637
638                         addresses = str_list_add(addresses, addresses_1c[i]);
639                         if (!addresses) {
640                                 goto notfound;
641                         }
642                 }
643         }
644
645 found:
646         nbtd_name_query_reply(nbtsock, packet, src, name, 
647                               0, nb_flags, addresses);
648         return;
649
650 notfound:
651         nbtd_negative_name_query_reply(nbtsock, packet, src);
652 }
653
654 /*
655   release a name
656 */
657 static void nbtd_winsserver_release(struct nbt_name_socket *nbtsock, 
658                                     struct nbt_name_packet *packet, 
659                                     struct socket_address *src)
660 {
661         NTSTATUS status;
662         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
663                                                        struct nbtd_interface);
664         struct wins_server *winssrv = iface->nbtsrv->winssrv;
665         struct nbt_name *name = &packet->questions[0].name;
666         struct winsdb_record *rec;
667         uint32_t modify_flags = 0;
668         uint8_t ret;
669
670         if (name->type == NBT_NAME_MASTER) {
671                 goto done;
672         }
673
674         status = winsdb_lookup(winssrv->wins_db, name, packet, &rec);
675         if (!NT_STATUS_IS_OK(status)) {
676                 goto done;
677         }
678
679         if (rec->is_static) {
680                 if (rec->type == WREPL_TYPE_UNIQUE || rec->type == WREPL_TYPE_MHOMED) {
681                         goto done;
682                 }
683                 nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_ACT);
684                 return;
685         }
686
687         if (rec->state != WREPL_STATE_ACTIVE) {
688                 goto done;
689         }
690
691         /* 
692          * TODO: do we need to check if
693          *       src->addr matches packet->additional[0].rdata.netbios.addresses[0].ipaddr
694          *       here?
695          */
696
697         /* 
698          * we only allow releases from an owner - other releases are
699          * silently ignored
700          */
701         if (!winsdb_addr_list_check(rec->addresses, src->addr)) {
702                 int i;
703                 DEBUG(4,("WINS: silently ignoring attempted name release on %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
704                 DEBUGADD(4, ("Registered Addressss: \n"));
705                 for (i=0; rec->addresses && rec->addresses[i]; i++) {
706                         DEBUGADD(4, ("%s\n", rec->addresses[i]->address));
707                 }
708                 goto done;
709         }
710
711         DEBUG(4,("WINS: released name %s from %s\n", nbt_name_string(rec, rec->name), src->addr));
712
713         switch (rec->type) {
714         case WREPL_TYPE_UNIQUE:
715                 rec->state = WREPL_STATE_RELEASED;
716                 break;
717
718         case WREPL_TYPE_GROUP:
719                 rec->state = WREPL_STATE_RELEASED;
720                 break;
721
722         case WREPL_TYPE_SGROUP:
723                 winsdb_addr_list_remove(rec->addresses, src->addr);
724                 /* TODO: do we need to take the ownership here? */
725                 if (winsdb_addr_list_length(rec->addresses) == 0) {
726                         rec->state = WREPL_STATE_RELEASED;
727                 }
728                 break;
729
730         case WREPL_TYPE_MHOMED:
731                 winsdb_addr_list_remove(rec->addresses, src->addr);
732                 /* TODO: do we need to take the ownership here? */
733                 if (winsdb_addr_list_length(rec->addresses) == 0) {
734                         rec->state = WREPL_STATE_RELEASED;
735                 }
736                 break;
737         }
738
739         if (rec->state == WREPL_STATE_RELEASED) {
740                 /*
741                  * if we're not the owner, we need to take the owner ship
742                  * and make the record tombstone, but expire after
743                  * tombstone_interval + tombstone_timeout and not only after tombstone_timeout
744                  * like for normal tombstone records.
745                  * This is to replicate the record directly to the original owner,
746                  * where the record is still active
747                  */ 
748                 if (strcmp(rec->wins_owner, winssrv->wins_db->local_owner) == 0) {
749                         rec->expire_time= time(NULL) + winssrv->config.tombstone_interval;
750                 } else {
751                         rec->state      = WREPL_STATE_TOMBSTONE;
752                         rec->expire_time= time(NULL) + 
753                                           winssrv->config.tombstone_interval +
754                                           winssrv->config.tombstone_timeout;
755                         modify_flags    = WINSDB_FLAG_ALLOC_VERSION | WINSDB_FLAG_TAKE_OWNERSHIP;
756                 }
757         }
758
759         ret = winsdb_modify(winssrv->wins_db, rec, modify_flags);
760         if (ret != NBT_RCODE_OK) {
761                 DEBUG(1,("WINS: FAILED: released name %s at %s: error:%u\n",
762                         nbt_name_string(rec, rec->name), src->addr, ret));
763         }
764 done:
765         /* we match w2k3 by always giving a positive reply to name releases. */
766         nbtd_name_release_reply(nbtsock, packet, src, NBT_RCODE_OK);
767 }
768
769
770 /*
771   answer a name query
772 */
773 void nbtd_winsserver_request(struct nbt_name_socket *nbtsock, 
774                              struct nbt_name_packet *packet, 
775                              struct socket_address *src)
776 {
777         struct nbtd_interface *iface = talloc_get_type(nbtsock->incoming.private, 
778                                                        struct nbtd_interface);
779         struct wins_server *winssrv = iface->nbtsrv->winssrv;
780         if ((packet->operation & NBT_FLAG_BROADCAST) || winssrv == NULL) {
781                 return;
782         }
783
784         switch (packet->operation & NBT_OPCODE) {
785         case NBT_OPCODE_QUERY:
786                 nbtd_winsserver_query(nbtsock, packet, src);
787                 break;
788
789         case NBT_OPCODE_REGISTER:
790         case NBT_OPCODE_REFRESH:
791         case NBT_OPCODE_REFRESH2:
792         case NBT_OPCODE_MULTI_HOME_REG:
793                 nbtd_winsserver_register(nbtsock, packet, src);
794                 break;
795
796         case NBT_OPCODE_RELEASE:
797                 nbtd_winsserver_release(nbtsock, packet, src);
798                 break;
799         }
800
801 }
802
803 /*
804   startup the WINS server, if configured
805 */
806 NTSTATUS nbtd_winsserver_init(struct nbtd_server *nbtsrv)
807 {
808         uint32_t tmp;
809
810         if (!lp_wins_support()) {
811                 nbtsrv->winssrv = NULL;
812                 return NT_STATUS_OK;
813         }
814
815         nbtsrv->winssrv = talloc_zero(nbtsrv, struct wins_server);
816         NT_STATUS_HAVE_NO_MEMORY(nbtsrv->winssrv);
817
818         nbtsrv->winssrv->config.max_renew_interval = lp_max_wins_ttl();
819         nbtsrv->winssrv->config.min_renew_interval = lp_min_wins_ttl();
820         tmp = lp_parm_int(-1,"wreplsrv","tombstone_interval", 6*24*60*60);
821         nbtsrv->winssrv->config.tombstone_interval = tmp;
822         tmp = lp_parm_int(-1,"wreplsrv","tombstone_timeout", 1*24*60*60);
823         nbtsrv->winssrv->config.tombstone_timeout = tmp;
824
825         nbtsrv->winssrv->wins_db     = winsdb_connect(nbtsrv->winssrv);
826         if (!nbtsrv->winssrv->wins_db) {
827                 return NT_STATUS_INTERNAL_DB_ERROR;
828         }
829
830         irpc_add_name(nbtsrv->task->msg_ctx, "wins_server");
831
832         return NT_STATUS_OK;
833 }