2 Unix SMB/CIFS implementation.
4 core wins server handling
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/winsdb.h"
26 #include "system/time.h"
29 work out the ttl we will use given a client requested ttl
31 uint32_t wins_server_ttl(struct wins_server
*winssrv
, uint32_t ttl
)
33 ttl
= MIN(ttl
, winssrv
->max_ttl
);
34 ttl
= MAX(ttl
, winssrv
->min_ttl
);
39 register a new name with WINS
41 static uint8_t wins_register_new(struct nbt_name_socket
*nbtsock
,
42 struct nbt_name_packet
*packet
,
43 const char *src_address
, int src_port
)
45 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
46 struct nbtd_interface
);
47 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
48 struct nbt_name
*name
= &packet
->questions
[0].name
;
49 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
50 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
51 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
52 struct winsdb_record rec
;
55 rec
.nb_flags
= nb_flags
;
56 rec
.state
= WINS_REC_ACTIVE
;
57 rec
.expire_time
= time(NULL
) + ttl
;
58 rec
.registered_by
= src_address
;
59 if (IS_GROUP_NAME(name
, nb_flags
)) {
60 rec
.addresses
= str_list_make(packet
, "255.255.255.255", NULL
);
62 rec
.addresses
= str_list_make(packet
, address
, NULL
);
64 if (rec
.addresses
== NULL
) return NBT_RCODE_SVR
;
66 DEBUG(4,("WINS: accepted registration of %s with address %s\n",
67 nbt_name_string(packet
, name
), rec
.addresses
[0]));
69 return winsdb_add(winssrv
, &rec
);
74 update the ttl on an existing record
76 static uint8_t wins_update_ttl(struct nbt_name_socket
*nbtsock
,
77 struct nbt_name_packet
*packet
,
78 struct winsdb_record
*rec
,
79 const char *src_address
, int src_port
)
81 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
82 struct nbtd_interface
);
83 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
84 uint32_t ttl
= wins_server_ttl(winssrv
, packet
->additional
[0].ttl
);
85 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
86 time_t now
= time(NULL
);
88 if (now
+ ttl
> rec
->expire_time
) {
89 rec
->expire_time
= now
+ ttl
;
91 rec
->registered_by
= src_address
;
93 DEBUG(5,("WINS: refreshed registration of %s at %s\n",
94 nbt_name_string(packet
, rec
->name
), address
));
96 return winsdb_modify(winssrv
, rec
);
102 static void nbtd_winsserver_register(struct nbt_name_socket
*nbtsock
,
103 struct nbt_name_packet
*packet
,
104 const char *src_address
, int src_port
)
106 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
107 struct nbtd_interface
);
108 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
109 struct nbt_name
*name
= &packet
->questions
[0].name
;
110 struct winsdb_record
*rec
;
111 uint8_t rcode
= NBT_RCODE_OK
;
112 uint16_t nb_flags
= packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
;
113 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
115 /* as a special case, the local master browser name is always accepted
116 for registration, but never stored */
117 if (name
->type
== NBT_NAME_MASTER
) {
121 rec
= winsdb_load(winssrv
, name
, packet
);
123 rcode
= wins_register_new(nbtsock
, packet
, src_address
, src_port
);
125 } else if (rec
->state
!= WINS_REC_ACTIVE
) {
126 winsdb_delete(winssrv
, rec
->name
);
127 rcode
= wins_register_new(nbtsock
, packet
, src_address
, src_port
);
131 /* its an active name - first see if the registration is of the right type */
132 if ((rec
->nb_flags
& NBT_NM_GROUP
) && !(nb_flags
& NBT_NM_GROUP
)) {
133 DEBUG(2,("WINS: Attempt to register unique name %s when group name is active\n",
134 nbt_name_string(packet
, name
)));
135 rcode
= NBT_RCODE_ACT
;
139 /* if its an active unique name, and the registration is for a group, then
140 see if the unique name owner still wants the name */
141 if (!(rec
->nb_flags
& NBT_NM_GROUP
) && (nb_flags
& NBT_NM_GROUP
)) {
142 wins_register_wack(nbtsock
, packet
, rec
, src_address
, src_port
);
146 /* if the registration is for a group, then just update the expiry time
148 if (IS_GROUP_NAME(name
, nb_flags
)) {
149 wins_update_ttl(nbtsock
, packet
, rec
, src_address
, src_port
);
153 /* if the registration is for an address that is currently active, then
154 just update the expiry time */
155 if (str_list_check(rec
->addresses
, address
)) {
156 wins_update_ttl(nbtsock
, packet
, rec
, src_address
, src_port
);
160 /* we have to do a WACK to see if the current owner is willing
161 to give up its claim */
162 wins_register_wack(nbtsock
, packet
, rec
, src_address
, src_port
);
166 nbtd_name_registration_reply(nbtsock
, packet
, src_address
, src_port
, rcode
);
174 static void nbtd_winsserver_query(struct nbt_name_socket
*nbtsock
,
175 struct nbt_name_packet
*packet
,
176 const char *src_address
, int src_port
)
178 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
179 struct nbtd_interface
);
180 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
181 struct nbt_name
*name
= &packet
->questions
[0].name
;
182 struct winsdb_record
*rec
;
184 rec
= winsdb_load(winssrv
, name
, packet
);
185 if (rec
== NULL
|| rec
->state
!= WINS_REC_ACTIVE
) {
186 nbtd_negative_name_query_reply(nbtsock
, packet
, src_address
, src_port
);
190 nbtd_name_query_reply(nbtsock
, packet
, src_address
, src_port
, name
,
191 0, rec
->nb_flags
, rec
->addresses
);
197 static void nbtd_winsserver_release(struct nbt_name_socket
*nbtsock
,
198 struct nbt_name_packet
*packet
,
199 const char *src_address
, int src_port
)
201 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
202 struct nbtd_interface
);
203 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
204 struct nbt_name
*name
= &packet
->questions
[0].name
;
205 struct winsdb_record
*rec
;
207 rec
= winsdb_load(winssrv
, name
, packet
);
209 rec
->state
!= WINS_REC_ACTIVE
||
210 IS_GROUP_NAME(name
, rec
->nb_flags
)) {
214 /* we only allow releases from an owner - other releases are
216 if (str_list_check(rec
->addresses
, src_address
)) {
217 const char *address
= packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
;
219 DEBUG(4,("WINS: released name %s at %s\n", nbt_name_string(rec
, rec
->name
), address
));
220 str_list_remove(rec
->addresses
, address
);
221 if (rec
->addresses
[0] == NULL
) {
222 rec
->state
= WINS_REC_RELEASED
;
224 winsdb_modify(winssrv
, rec
);
228 /* we match w2k3 by always giving a positive reply to name releases. */
229 nbtd_name_release_reply(nbtsock
, packet
, src_address
, src_port
, NBT_RCODE_OK
);
236 void nbtd_winsserver_request(struct nbt_name_socket
*nbtsock
,
237 struct nbt_name_packet
*packet
,
238 const char *src_address
, int src_port
)
240 struct nbtd_interface
*iface
= talloc_get_type(nbtsock
->incoming
.private,
241 struct nbtd_interface
);
242 struct wins_server
*winssrv
= iface
->nbtsrv
->winssrv
;
243 if ((packet
->operation
& NBT_FLAG_BROADCAST
) || winssrv
== NULL
) {
247 switch (packet
->operation
& NBT_OPCODE
) {
248 case NBT_OPCODE_QUERY
:
249 nbtd_winsserver_query(nbtsock
, packet
, src_address
, src_port
);
252 case NBT_OPCODE_REGISTER
:
253 case NBT_OPCODE_REFRESH
:
254 case NBT_OPCODE_REFRESH2
:
255 case NBT_OPCODE_MULTI_HOME_REG
:
256 nbtd_winsserver_register(nbtsock
, packet
, src_address
, src_port
);
259 case NBT_OPCODE_RELEASE
:
260 nbtd_winsserver_release(nbtsock
, packet
, src_address
, src_port
);
267 startup the WINS server, if configured
269 NTSTATUS
nbtd_winsserver_init(struct nbtd_server
*nbtsrv
)
271 if (!lp_wins_support()) {
272 nbtsrv
->winssrv
= NULL
;
276 nbtsrv
->winssrv
= talloc(nbtsrv
, struct wins_server
);
277 NT_STATUS_HAVE_NO_MEMORY(nbtsrv
->winssrv
);
279 nbtsrv
->winssrv
->max_ttl
= lp_max_wins_ttl();
280 nbtsrv
->winssrv
->min_ttl
= lp_min_wins_ttl();
282 return winsdb_init(nbtsrv
->winssrv
);