libcli/nbt: convert nbt_name_register_wins_send/recv to tevent_req
[Samba/gebeck_regimport.git] / libcli / nbt / nameregister.c
blob4d307d9564b01d40442e8c5342ca6abe54aac3bd
1 /*
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/>.
22 #include "includes.h"
23 #include <tevent.h>
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;
44 packet->qdcount = 1;
45 packet->arcount = 1;
46 if (io->in.multi_homed) {
47 packet->operation = NBT_OPCODE_MULTI_HOME_REG;
48 } else {
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;
88 talloc_free(packet);
89 return req;
91 failed:
92 talloc_free(packet);
93 return NULL;
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)
102 NTSTATUS status;
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) {
108 talloc_free(req);
109 return status;
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) {
118 talloc_free(req);
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) {
125 talloc_free(req);
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);
133 talloc_free(req);
135 return NT_STATUS_OK;
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);
167 NTSTATUS status;
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) {
172 /* all done */
173 c->state = COMPOSITE_STATE_DONE;
174 c->status = NT_STATUS_OK;
175 goto done;
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;
185 } else {
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;
191 c->status = status;
192 } else {
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));
202 done:
203 if (c->state >= COMPOSITE_STATE_DONE &&
204 c->async.fn) {
205 c->async.fn(c);
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;
251 return c;
253 failed:
254 talloc_free(c);
255 return NULL;
259 broadcast 4 part name register - recv
261 _PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c)
263 NTSTATUS status;
264 status = composite_wait(c);
265 talloc_free(c);
266 return status;
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;
288 char **wins_servers;
289 uint16_t wins_port;
290 char **addresses;
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);
310 if (req == NULL) {
311 return NULL;
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;
368 return 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,
378 struct tevent_req);
379 struct nbt_name_register_wins_state *state =
380 tevent_req_data(req,
381 struct nbt_name_register_wins_state);
382 NTSTATUS status;
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);
390 return;
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)) {
400 return;
403 subreq->async.fn = nbt_name_register_wins_handler;
404 subreq->async.private_data = req;
405 return;
408 if (!NT_STATUS_IS_OK(status)) {
409 tevent_req_nterror(req, status);
410 return;
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)) {
420 return;
423 subreq->async.fn = nbt_name_register_wins_handler;
424 subreq->async.private_data = req;
425 return;
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,
435 TALLOC_CTX *mem_ctx,
436 struct nbt_name_register_wins *io)
438 struct nbt_name_register_wins_state *state =
439 tevent_req_data(req,
440 struct nbt_name_register_wins_state);
441 NTSTATUS status;
443 if (tevent_req_is_nterror(req, &status)) {
444 tevent_req_received(req);
445 return status;
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);
452 return NT_STATUS_OK;
456 multi-homed WINS register - sync interface
458 _PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
459 TALLOC_CTX *mem_ctx,
460 struct nbt_name_register_wins *io)
462 TALLOC_CTX *frame = talloc_stackframe();
463 struct tevent_context *ev;
464 struct tevent_req *subreq;
465 NTSTATUS status;
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) {
474 talloc_free(frame);
475 return NT_STATUS_NO_MEMORY;
478 if (!tevent_req_poll(subreq, ev)) {
479 status = map_nt_error_from_unix(errno);
480 talloc_free(frame);
481 return status;
484 status = nbt_name_register_wins_recv(subreq, mem_ctx, io);
485 if (!NT_STATUS_IS_OK(status)) {
486 talloc_free(frame);
487 return status;
490 TALLOC_FREE(frame);
491 return NT_STATUS_OK;