2 Unix SMB/CIFS implementation.
4 send out a name registration request
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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "../libcli/nbt/libnbt.h"
25 #include "../libcli/nbt/nbt_proto.h"
26 #include "libcli/composite/composite.h"
27 #include "lib/socket/socket.h"
28 #include "librpc/gen_ndr/ndr_nbt.h"
29 #include "../lib/util/tevent_ntstatus.h"
32 send a nbt name registration request
34 struct nbt_name_request
*nbt_name_register_send(struct nbt_name_socket
*nbtsock
,
35 struct nbt_name_register
*io
)
37 struct nbt_name_request
*req
;
38 struct nbt_name_packet
*packet
;
39 struct socket_address
*dest
;
41 packet
= talloc_zero(nbtsock
, struct nbt_name_packet
);
42 if (packet
== NULL
) return NULL
;
46 if (io
->in
.multi_homed
) {
47 packet
->operation
= NBT_OPCODE_MULTI_HOME_REG
;
49 packet
->operation
= NBT_OPCODE_REGISTER
;
51 if (io
->in
.broadcast
) {
52 packet
->operation
|= NBT_FLAG_BROADCAST
;
54 if (io
->in
.register_demand
) {
55 packet
->operation
|= NBT_FLAG_RECURSION_DESIRED
;
58 packet
->questions
= talloc_array(packet
, struct nbt_name_question
, 1);
59 if (packet
->questions
== NULL
) goto failed
;
61 packet
->questions
[0].name
= io
->in
.name
;
62 packet
->questions
[0].question_type
= NBT_QTYPE_NETBIOS
;
63 packet
->questions
[0].question_class
= NBT_QCLASS_IP
;
65 packet
->additional
= talloc_array(packet
, struct nbt_res_rec
, 1);
66 if (packet
->additional
== NULL
) goto failed
;
68 packet
->additional
[0].name
= io
->in
.name
;
69 packet
->additional
[0].rr_type
= NBT_QTYPE_NETBIOS
;
70 packet
->additional
[0].rr_class
= NBT_QCLASS_IP
;
71 packet
->additional
[0].ttl
= io
->in
.ttl
;
72 packet
->additional
[0].rdata
.netbios
.length
= 6;
73 packet
->additional
[0].rdata
.netbios
.addresses
= talloc_array(packet
->additional
,
74 struct nbt_rdata_address
, 1);
75 if (packet
->additional
[0].rdata
.netbios
.addresses
== NULL
) goto failed
;
76 packet
->additional
[0].rdata
.netbios
.addresses
[0].nb_flags
= io
->in
.nb_flags
;
77 packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
=
78 talloc_strdup(packet
->additional
, io
->in
.address
);
79 if (packet
->additional
[0].rdata
.netbios
.addresses
[0].ipaddr
== NULL
) goto failed
;
81 dest
= socket_address_from_strings(packet
, nbtsock
->sock
->backend_name
,
82 io
->in
.dest_addr
, io
->in
.dest_port
);
83 if (dest
== NULL
) goto failed
;
84 req
= nbt_name_request_send(nbtsock
, dest
, packet
,
85 io
->in
.timeout
, io
->in
.retries
, false);
86 if (req
== NULL
) goto failed
;
97 wait for a registration reply
99 _PUBLIC_ NTSTATUS
nbt_name_register_recv(struct nbt_name_request
*req
,
100 TALLOC_CTX
*mem_ctx
, struct nbt_name_register
*io
)
103 struct nbt_name_packet
*packet
;
105 status
= nbt_name_request_recv(req
);
106 if (!NT_STATUS_IS_OK(status
) ||
107 req
->num_replies
== 0) {
112 packet
= req
->replies
[0].packet
;
113 io
->out
.reply_from
= talloc_steal(mem_ctx
, req
->replies
[0].dest
->addr
);
115 if (packet
->ancount
!= 1 ||
116 packet
->answers
[0].rr_type
!= NBT_QTYPE_NETBIOS
||
117 packet
->answers
[0].rr_class
!= NBT_QCLASS_IP
) {
119 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
122 io
->out
.rcode
= packet
->operation
& NBT_RCODE
;
123 io
->out
.name
= packet
->answers
[0].name
;
124 if (packet
->answers
[0].rdata
.netbios
.length
< 6) {
126 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
128 io
->out
.reply_addr
= talloc_steal(mem_ctx
,
129 packet
->answers
[0].rdata
.netbios
.addresses
[0].ipaddr
);
130 talloc_steal(mem_ctx
, io
->out
.name
.name
);
131 talloc_steal(mem_ctx
, io
->out
.name
.scope
);
139 synchronous name registration request
141 _PUBLIC_ NTSTATUS
nbt_name_register(struct nbt_name_socket
*nbtsock
,
142 TALLOC_CTX
*mem_ctx
, struct nbt_name_register
*io
)
144 struct nbt_name_request
*req
= nbt_name_register_send(nbtsock
, io
);
145 return nbt_name_register_recv(req
, mem_ctx
, io
);
150 a 4 step broadcast registration. 3 lots of name registration requests, followed by
151 a name registration demand
153 struct register_bcast_state
{
154 struct nbt_name_socket
*nbtsock
;
155 struct nbt_name_register
*io
;
156 struct nbt_name_request
*req
;
161 state handler for 4 stage name registration
163 static void name_register_bcast_handler(struct nbt_name_request
*req
)
165 struct composite_context
*c
= talloc_get_type(req
->async
.private_data
, struct composite_context
);
166 struct register_bcast_state
*state
= talloc_get_type(c
->private_data
, struct register_bcast_state
);
169 status
= nbt_name_register_recv(state
->req
, state
, state
->io
);
170 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
171 if (state
->io
->in
.register_demand
== true) {
173 c
->state
= COMPOSITE_STATE_DONE
;
174 c
->status
= NT_STATUS_OK
;
178 /* the registration timed out - good, send the demand */
179 state
->io
->in
.register_demand
= true;
180 state
->io
->in
.retries
= 0;
181 state
->req
= nbt_name_register_send(state
->nbtsock
, state
->io
);
182 if (state
->req
== NULL
) {
183 c
->state
= COMPOSITE_STATE_ERROR
;
184 c
->status
= NT_STATUS_NO_MEMORY
;
186 state
->req
->async
.fn
= name_register_bcast_handler
;
187 state
->req
->async
.private_data
= c
;
189 } else if (!NT_STATUS_IS_OK(status
)) {
190 c
->state
= COMPOSITE_STATE_ERROR
;
193 c
->state
= COMPOSITE_STATE_ERROR
;
194 c
->status
= NT_STATUS_CONFLICTING_ADDRESSES
;
195 DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
196 state
->io
->out
.reply_from
,
197 nbt_name_string(state
, &state
->io
->out
.name
),
198 state
->io
->out
.reply_addr
,
199 state
->io
->out
.rcode
));
203 if (c
->state
>= COMPOSITE_STATE_DONE
&&
210 the async send call for a 4 stage name registration
212 _PUBLIC_
struct composite_context
*nbt_name_register_bcast_send(struct nbt_name_socket
*nbtsock
,
213 struct nbt_name_register_bcast
*io
)
215 struct composite_context
*c
;
216 struct register_bcast_state
*state
;
218 c
= talloc_zero(nbtsock
, struct composite_context
);
219 if (c
== NULL
) goto failed
;
221 state
= talloc(c
, struct register_bcast_state
);
222 if (state
== NULL
) goto failed
;
224 state
->io
= talloc(state
, struct nbt_name_register
);
225 if (state
->io
== NULL
) goto failed
;
227 state
->io
->in
.name
= io
->in
.name
;
228 state
->io
->in
.dest_addr
= io
->in
.dest_addr
;
229 state
->io
->in
.dest_port
= io
->in
.dest_port
;
230 state
->io
->in
.address
= io
->in
.address
;
231 state
->io
->in
.nb_flags
= io
->in
.nb_flags
;
232 state
->io
->in
.register_demand
= false;
233 state
->io
->in
.broadcast
= true;
234 state
->io
->in
.multi_homed
= false;
235 state
->io
->in
.ttl
= io
->in
.ttl
;
236 state
->io
->in
.timeout
= 1;
237 state
->io
->in
.retries
= 2;
239 state
->nbtsock
= nbtsock
;
241 state
->req
= nbt_name_register_send(nbtsock
, state
->io
);
242 if (state
->req
== NULL
) goto failed
;
244 state
->req
->async
.fn
= name_register_bcast_handler
;
245 state
->req
->async
.private_data
= c
;
247 c
->private_data
= state
;
248 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
249 c
->event_ctx
= nbtsock
->event_ctx
;
259 broadcast 4 part name register - recv
261 _PUBLIC_ NTSTATUS
nbt_name_register_bcast_recv(struct composite_context
*c
)
264 status
= composite_wait(c
);
270 broadcast 4 part name register - sync interface
272 NTSTATUS
nbt_name_register_bcast(struct nbt_name_socket
*nbtsock
,
273 struct nbt_name_register_bcast
*io
)
275 struct composite_context
*c
= nbt_name_register_bcast_send(nbtsock
, io
);
276 return nbt_name_register_bcast_recv(c
);
281 a wins name register with multiple WINS servers and multiple
282 addresses to register. Try each WINS server in turn, until we get a
283 reply for each address
285 struct nbt_name_register_wins_state
{
286 struct nbt_name_socket
*nbtsock
;
287 struct nbt_name_register io
;
291 uint32_t address_idx
;
294 static void nbt_name_register_wins_handler(struct nbt_name_request
*subreq
);
297 the async send call for a multi-server WINS register
299 _PUBLIC_
struct tevent_req
*nbt_name_register_wins_send(TALLOC_CTX
*mem_ctx
,
300 struct tevent_context
*ev
,
301 struct nbt_name_socket
*nbtsock
,
302 struct nbt_name_register_wins
*io
)
304 struct tevent_req
*req
;
305 struct nbt_name_register_wins_state
*state
;
306 struct nbt_name_request
*subreq
;
308 req
= tevent_req_create(mem_ctx
, &state
,
309 struct nbt_name_register_wins_state
);
314 if (io
->in
.wins_servers
== NULL
) {
315 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
316 return tevent_req_post(req
, ev
);
319 if (io
->in
.wins_servers
[0] == NULL
) {
320 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
321 return tevent_req_post(req
, ev
);
324 if (io
->in
.addresses
== NULL
) {
325 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
326 return tevent_req_post(req
, ev
);
329 if (io
->in
.addresses
[0] == NULL
) {
330 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
331 return tevent_req_post(req
, ev
);
334 state
->wins_port
= io
->in
.wins_port
;
335 state
->wins_servers
= str_list_copy(state
, io
->in
.wins_servers
);
336 if (tevent_req_nomem(state
->wins_servers
, req
)) {
337 return tevent_req_post(req
, ev
);
340 state
->addresses
= str_list_copy(state
, io
->in
.addresses
);
341 if (tevent_req_nomem(state
->addresses
, req
)) {
342 return tevent_req_post(req
, ev
);
345 state
->io
.in
.name
= io
->in
.name
;
346 state
->io
.in
.dest_addr
= state
->wins_servers
[0];
347 state
->io
.in
.dest_port
= state
->wins_port
;
348 state
->io
.in
.address
= io
->in
.addresses
[0];
349 state
->io
.in
.nb_flags
= io
->in
.nb_flags
;
350 state
->io
.in
.broadcast
= false;
351 state
->io
.in
.register_demand
= false;
352 state
->io
.in
.multi_homed
= (io
->in
.nb_flags
& NBT_NM_GROUP
)?false:true;
353 state
->io
.in
.ttl
= io
->in
.ttl
;
354 state
->io
.in
.timeout
= 3;
355 state
->io
.in
.retries
= 2;
357 state
->nbtsock
= nbtsock
;
358 state
->address_idx
= 0;
360 subreq
= nbt_name_register_send(nbtsock
, &state
->io
);
361 if (tevent_req_nomem(subreq
, req
)) {
362 return tevent_req_post(req
, ev
);
365 subreq
->async
.fn
= nbt_name_register_wins_handler
;
366 subreq
->async
.private_data
= req
;
372 state handler for WINS multi-homed multi-server name register
374 static void nbt_name_register_wins_handler(struct nbt_name_request
*subreq
)
376 struct tevent_req
*req
=
377 talloc_get_type_abort(subreq
->async
.private_data
,
379 struct nbt_name_register_wins_state
*state
=
381 struct nbt_name_register_wins_state
);
384 status
= nbt_name_register_recv(subreq
, state
, &state
->io
);
385 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
386 /* the register timed out - try the next WINS server */
387 state
->wins_servers
++;
388 if (state
->wins_servers
[0] == NULL
) {
389 tevent_req_nterror(req
, status
);
393 state
->address_idx
= 0;
394 state
->io
.in
.dest_addr
= state
->wins_servers
[0];
395 state
->io
.in
.dest_port
= state
->wins_port
;
396 state
->io
.in
.address
= state
->addresses
[0];
398 subreq
= nbt_name_register_send(state
->nbtsock
, &state
->io
);
399 if (tevent_req_nomem(subreq
, req
)) {
403 subreq
->async
.fn
= nbt_name_register_wins_handler
;
404 subreq
->async
.private_data
= req
;
408 if (!NT_STATUS_IS_OK(status
)) {
409 tevent_req_nterror(req
, status
);
413 if (state
->io
.out
.rcode
== 0 &&
414 state
->addresses
[state
->address_idx
+1] != NULL
) {
415 /* register our next address */
416 state
->io
.in
.address
= state
->addresses
[++(state
->address_idx
)];
418 subreq
= nbt_name_register_send(state
->nbtsock
, &state
->io
);
419 if (tevent_req_nomem(subreq
, req
)) {
423 subreq
->async
.fn
= nbt_name_register_wins_handler
;
424 subreq
->async
.private_data
= req
;
428 tevent_req_done(req
);
432 multi-homed WINS name register - recv side
434 _PUBLIC_ NTSTATUS
nbt_name_register_wins_recv(struct tevent_req
*req
,
436 struct nbt_name_register_wins
*io
)
438 struct nbt_name_register_wins_state
*state
=
440 struct nbt_name_register_wins_state
);
443 if (tevent_req_is_nterror(req
, &status
)) {
444 tevent_req_received(req
);
448 io
->out
.wins_server
= talloc_move(mem_ctx
, &state
->wins_servers
[0]);
449 io
->out
.rcode
= state
->io
.out
.rcode
;
451 tevent_req_received(req
);
456 multi-homed WINS register - sync interface
458 _PUBLIC_ NTSTATUS
nbt_name_register_wins(struct nbt_name_socket
*nbtsock
,
460 struct nbt_name_register_wins
*io
)
462 TALLOC_CTX
*frame
= talloc_stackframe();
463 struct tevent_context
*ev
;
464 struct tevent_req
*subreq
;
468 * TODO: create a temporary event context
470 ev
= nbtsock
->event_ctx
;
472 subreq
= nbt_name_register_wins_send(frame
, ev
, nbtsock
, io
);
473 if (subreq
== NULL
) {
475 return NT_STATUS_NO_MEMORY
;
478 if (!tevent_req_poll(subreq
, ev
)) {
479 status
= map_nt_error_from_unix(errno
);
484 status
= nbt_name_register_wins_recv(subreq
, mem_ctx
, io
);
485 if (!NT_STATUS_IS_OK(status
)) {