2 Unix SMB/CIFS implementation.
4 "secure" wins server WACK processing
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher 2005
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 3 of the License, or
12 (at your option) any later version.
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.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "nbt_server/nbt_server.h"
25 #include "nbt_server/wins/winsdb.h"
26 #include "nbt_server/wins/winsserver.h"
27 #include "system/time.h"
28 #include "libcli/composite/composite.h"
29 #include "param/param.h"
30 #include "smbd/service_task.h"
32 struct wins_challenge_state
{
33 struct wins_challenge_io
*io
;
34 uint32_t current_address
;
35 struct nbt_name_query query
;
38 static void wins_challenge_handler(struct nbt_name_request
*req
)
40 struct composite_context
*ctx
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
41 struct wins_challenge_state
*state
= talloc_get_type(ctx
->private_data
, struct wins_challenge_state
);
43 ctx
->status
= nbt_name_query_recv(req
, state
, &state
->query
);
45 /* if we timed out then try the next owner address, if any */
46 if (NT_STATUS_EQUAL(ctx
->status
, NT_STATUS_IO_TIMEOUT
)) {
47 state
->current_address
++;
48 if (state
->current_address
< state
->io
->in
.num_addresses
) {
49 struct nbtd_interface
*iface
;
51 state
->query
.in
.dest_port
= state
->io
->in
.nbt_port
;
52 state
->query
.in
.dest_addr
= state
->io
->in
.addresses
[state
->current_address
];
54 iface
= nbtd_find_request_iface(state
->io
->in
.nbtd_server
, state
->query
.in
.dest_addr
, true);
56 composite_error(ctx
, NT_STATUS_INTERNAL_ERROR
);
60 ZERO_STRUCT(state
->query
.out
);
61 req
= nbt_name_query_send(iface
->nbtsock
, &state
->query
);
62 composite_continue_nbt(ctx
, req
, wins_challenge_handler
, ctx
);
70 NTSTATUS
wins_challenge_recv(struct composite_context
*ctx
, TALLOC_CTX
*mem_ctx
, struct wins_challenge_io
*io
)
72 NTSTATUS status
= ctx
->status
;
73 struct wins_challenge_state
*state
= talloc_get_type(ctx
->private_data
, struct wins_challenge_state
);
75 if (NT_STATUS_IS_OK(status
)) {
76 io
->out
.num_addresses
= state
->query
.out
.num_addrs
;
77 io
->out
.addresses
= state
->query
.out
.reply_addrs
;
78 talloc_steal(mem_ctx
, io
->out
.addresses
);
87 struct composite_context
*wins_challenge_send(TALLOC_CTX
*mem_ctx
, struct wins_challenge_io
*io
)
89 struct composite_context
*result
;
90 struct wins_challenge_state
*state
;
91 struct nbt_name_request
*req
;
92 struct nbtd_interface
*iface
;
94 result
= talloc_zero(mem_ctx
, struct composite_context
);
95 if (result
== NULL
) return NULL
;
96 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
97 result
->event_ctx
= talloc_reference(result
, io
->in
.event_ctx
);
99 state
= talloc_zero(result
, struct wins_challenge_state
);
100 if (state
== NULL
) goto failed
;
101 result
->private_data
= state
;
103 /* package up the state variables for this wack request */
105 state
->current_address
= 0;
107 /* setup a name query to the first address */
108 state
->query
.in
.name
= *state
->io
->in
.name
;
109 state
->query
.in
.dest_port
= state
->io
->in
.nbt_port
;
110 state
->query
.in
.dest_addr
= state
->io
->in
.addresses
[state
->current_address
];
111 state
->query
.in
.broadcast
= false;
112 state
->query
.in
.wins_lookup
= true;
113 state
->query
.in
.timeout
= 1;
114 state
->query
.in
.retries
= 2;
115 ZERO_STRUCT(state
->query
.out
);
117 iface
= nbtd_find_request_iface(state
->io
->in
.nbtd_server
, state
->query
.in
.dest_addr
, true);
122 req
= nbt_name_query_send(iface
->nbtsock
, &state
->query
);
123 if (req
== NULL
) goto failed
;
125 req
->async
.fn
= wins_challenge_handler
;
126 req
->async
.private_data
= result
;
134 struct wins_release_demand_io
{
136 struct nbtd_server
*nbtd_server
;
137 struct tevent_context
*event_ctx
;
138 struct nbt_name
*name
;
140 uint32_t num_addresses
;
141 const char **addresses
;
145 struct wins_release_demand_state
{
146 struct wins_release_demand_io
*io
;
147 uint32_t current_address
;
148 uint32_t addresses_left
;
149 struct nbt_name_release release
;
152 static void wins_release_demand_handler(struct nbt_name_request
*req
)
154 struct composite_context
*ctx
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
155 struct wins_release_demand_state
*state
= talloc_get_type(ctx
->private_data
, struct wins_release_demand_state
);
157 ctx
->status
= nbt_name_release_recv(req
, state
, &state
->release
);
159 /* if we timed out then try the next owner address, if any */
160 if (NT_STATUS_EQUAL(ctx
->status
, NT_STATUS_IO_TIMEOUT
)) {
161 state
->current_address
++;
162 state
->addresses_left
--;
163 if (state
->current_address
< state
->io
->in
.num_addresses
) {
164 struct nbtd_interface
*iface
;
166 state
->release
.in
.dest_port
= lp_nbt_port(state
->io
->in
.nbtd_server
->task
->lp_ctx
);
167 state
->release
.in
.dest_addr
= state
->io
->in
.addresses
[state
->current_address
];
168 state
->release
.in
.address
= state
->release
.in
.dest_addr
;
169 state
->release
.in
.timeout
= (state
->addresses_left
> 1 ? 2 : 1);
170 state
->release
.in
.retries
= (state
->addresses_left
> 1 ? 0 : 2);
172 iface
= nbtd_find_request_iface(state
->io
->in
.nbtd_server
, state
->release
.in
.dest_addr
, true);
174 composite_error(ctx
, NT_STATUS_INTERNAL_ERROR
);
178 ZERO_STRUCT(state
->release
.out
);
179 req
= nbt_name_release_send(iface
->nbtsock
, &state
->release
);
180 composite_continue_nbt(ctx
, req
, wins_release_demand_handler
, ctx
);
188 static NTSTATUS
wins_release_demand_recv(struct composite_context
*ctx
,
190 struct wins_release_demand_io
*io
)
192 NTSTATUS status
= ctx
->status
;
197 static struct composite_context
*wins_release_demand_send(TALLOC_CTX
*mem_ctx
, struct wins_release_demand_io
*io
)
199 struct composite_context
*result
;
200 struct wins_release_demand_state
*state
;
201 struct nbt_name_request
*req
;
202 struct nbtd_interface
*iface
;
204 result
= talloc_zero(mem_ctx
, struct composite_context
);
205 if (result
== NULL
) return NULL
;
206 result
->state
= COMPOSITE_STATE_IN_PROGRESS
;
207 result
->event_ctx
= talloc_reference(result
, io
->in
.event_ctx
);
209 state
= talloc_zero(result
, struct wins_release_demand_state
);
210 if (state
== NULL
) goto failed
;
211 result
->private_data
= state
;
213 /* package up the state variables for this wack request */
215 state
->current_address
= 0;
216 state
->addresses_left
= state
->io
->in
.num_addresses
;
219 * setup a name query to the first address
220 * - if we have more than one address try the first
221 * with 2 secs timeout and no retry
222 * - otherwise use 1 sec timeout (w2k3 uses 0.5 sec here)
225 state
->release
.in
.name
= *state
->io
->in
.name
;
226 state
->release
.in
.dest_port
= lp_nbt_port(state
->io
->in
.nbtd_server
->task
->lp_ctx
);
227 state
->release
.in
.dest_addr
= state
->io
->in
.addresses
[state
->current_address
];
228 state
->release
.in
.address
= state
->release
.in
.dest_addr
;
229 state
->release
.in
.broadcast
= false;
230 state
->release
.in
.timeout
= (state
->addresses_left
> 1 ? 2 : 1);
231 state
->release
.in
.retries
= (state
->addresses_left
> 1 ? 0 : 2);
232 ZERO_STRUCT(state
->release
.out
);
234 iface
= nbtd_find_request_iface(state
->io
->in
.nbtd_server
, state
->release
.in
.dest_addr
, true);
239 req
= nbt_name_release_send(iface
->nbtsock
, &state
->release
);
240 if (req
== NULL
) goto failed
;
242 req
->async
.fn
= wins_release_demand_handler
;
243 req
->async
.private_data
= result
;
252 wrepl_server needs to be able to do a name query request, but some windows
253 servers always send the reply to port 137, regardless of the request
254 port. To cope with this we use a irpc request to the NBT server
255 which has port 137 open, and thus can receive the replies
257 struct proxy_wins_challenge_state
{
258 struct irpc_message
*msg
;
259 struct nbtd_proxy_wins_challenge
*req
;
260 struct wins_challenge_io io
;
261 struct composite_context
*c_req
;
264 static void proxy_wins_challenge_handler(struct composite_context
*c_req
)
268 struct proxy_wins_challenge_state
*s
= talloc_get_type(c_req
->async
.private_data
,
269 struct proxy_wins_challenge_state
);
271 status
= wins_challenge_recv(s
->c_req
, s
, &s
->io
);
272 if (!NT_STATUS_IS_OK(status
)) {
273 ZERO_STRUCT(s
->req
->out
);
274 irpc_send_reply(s
->msg
, status
);
278 s
->req
->out
.num_addrs
= s
->io
.out
.num_addresses
;
279 /* TODO: fix pidl to handle inline ipv4address arrays */
280 s
->req
->out
.addrs
= talloc_array(s
->msg
, struct nbtd_proxy_wins_addr
,
281 s
->io
.out
.num_addresses
);
282 if (!s
->req
->out
.addrs
) {
283 ZERO_STRUCT(s
->req
->out
);
284 irpc_send_reply(s
->msg
, NT_STATUS_NO_MEMORY
);
287 for (i
=0; i
< s
->io
.out
.num_addresses
; i
++) {
288 s
->req
->out
.addrs
[i
].addr
= talloc_steal(s
->req
->out
.addrs
, s
->io
.out
.addresses
[i
]);
291 irpc_send_reply(s
->msg
, status
);
294 NTSTATUS
nbtd_proxy_wins_challenge(struct irpc_message
*msg
,
295 struct nbtd_proxy_wins_challenge
*req
)
297 struct nbtd_server
*nbtd_server
=
298 talloc_get_type(msg
->private_data
, struct nbtd_server
);
299 struct proxy_wins_challenge_state
*s
;
302 s
= talloc(msg
, struct proxy_wins_challenge_state
);
303 NT_STATUS_HAVE_NO_MEMORY(s
);
308 s
->io
.in
.nbtd_server
= nbtd_server
;
309 s
->io
.in
.nbt_port
= lp_nbt_port(nbtd_server
->task
->lp_ctx
);
310 s
->io
.in
.event_ctx
= msg
->ev
;
311 s
->io
.in
.name
= &req
->in
.name
;
312 s
->io
.in
.num_addresses
= req
->in
.num_addrs
;
313 s
->io
.in
.addresses
= talloc_array(s
, const char *, req
->in
.num_addrs
);
314 NT_STATUS_HAVE_NO_MEMORY(s
->io
.in
.addresses
);
315 /* TODO: fix pidl to handle inline ipv4address arrays */
316 for (i
=0; i
< req
->in
.num_addrs
; i
++) {
317 s
->io
.in
.addresses
[i
] = talloc_steal(s
->io
.in
.addresses
, req
->in
.addrs
[i
].addr
);
320 s
->c_req
= wins_challenge_send(s
, &s
->io
);
321 NT_STATUS_HAVE_NO_MEMORY(s
->c_req
);
323 s
->c_req
->async
.fn
= proxy_wins_challenge_handler
;
324 s
->c_req
->async
.private_data
= s
;
326 msg
->defer_reply
= true;
331 wrepl_server needs to be able to do a name release demands, but some windows
332 servers always send the reply to port 137, regardless of the request
333 port. To cope with this we use a irpc request to the NBT server
334 which has port 137 open, and thus can receive the replies
336 struct proxy_wins_release_demand_state
{
337 struct irpc_message
*msg
;
338 struct nbtd_proxy_wins_release_demand
*req
;
339 struct wins_release_demand_io io
;
340 struct composite_context
*c_req
;
343 static void proxy_wins_release_demand_handler(struct composite_context
*c_req
)
346 struct proxy_wins_release_demand_state
*s
= talloc_get_type(c_req
->async
.private_data
,
347 struct proxy_wins_release_demand_state
);
349 status
= wins_release_demand_recv(s
->c_req
, s
, &s
->io
);
351 irpc_send_reply(s
->msg
, status
);
354 NTSTATUS
nbtd_proxy_wins_release_demand(struct irpc_message
*msg
,
355 struct nbtd_proxy_wins_release_demand
*req
)
357 struct nbtd_server
*nbtd_server
=
358 talloc_get_type(msg
->private_data
, struct nbtd_server
);
359 struct proxy_wins_release_demand_state
*s
;
362 s
= talloc(msg
, struct proxy_wins_release_demand_state
);
363 NT_STATUS_HAVE_NO_MEMORY(s
);
368 s
->io
.in
.nbtd_server
= nbtd_server
;
369 s
->io
.in
.event_ctx
= msg
->ev
;
370 s
->io
.in
.name
= &req
->in
.name
;
371 s
->io
.in
.num_addresses
= req
->in
.num_addrs
;
372 s
->io
.in
.addresses
= talloc_array(s
, const char *, req
->in
.num_addrs
);
373 NT_STATUS_HAVE_NO_MEMORY(s
->io
.in
.addresses
);
374 /* TODO: fix pidl to handle inline ipv4address arrays */
375 for (i
=0; i
< req
->in
.num_addrs
; i
++) {
376 s
->io
.in
.addresses
[i
] = talloc_steal(s
->io
.in
.addresses
, req
->in
.addrs
[i
].addr
);
379 s
->c_req
= wins_release_demand_send(s
, &s
->io
);
380 NT_STATUS_HAVE_NO_MEMORY(s
->c_req
);
382 s
->c_req
->async
.fn
= proxy_wins_release_demand_handler
;
383 s
->c_req
->async
.private_data
= s
;
385 msg
->defer_reply
= true;