ctdb-protocol: Add missing push support for new controls
[Samba.git] / libcli / nbt / nameregister.c
blob8e8271d5731579ff2eefa6783efa4d69821d99d6
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 "lib/socket/socket.h"
27 #include "librpc/gen_ndr/ndr_nbt.h"
28 #include "../lib/util/tevent_ntstatus.h"
31 send a nbt name registration request
33 struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
34 struct nbt_name_register *io)
36 struct nbt_name_request *req;
37 struct nbt_name_packet *packet;
38 struct socket_address *dest;
40 packet = talloc_zero(nbtsock, struct nbt_name_packet);
41 if (packet == NULL) return NULL;
43 packet->qdcount = 1;
44 packet->arcount = 1;
45 if (io->in.multi_homed) {
46 packet->operation = NBT_OPCODE_MULTI_HOME_REG;
47 } else {
48 packet->operation = NBT_OPCODE_REGISTER;
50 if (io->in.broadcast) {
51 packet->operation |= NBT_FLAG_BROADCAST;
53 if (io->in.register_demand) {
54 packet->operation |= NBT_FLAG_RECURSION_DESIRED;
57 packet->questions = talloc_array(packet, struct nbt_name_question, 1);
58 if (packet->questions == NULL) goto failed;
60 packet->questions[0].name = io->in.name;
61 packet->questions[0].question_type = NBT_QTYPE_NETBIOS;
62 packet->questions[0].question_class = NBT_QCLASS_IP;
64 packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
65 if (packet->additional == NULL) goto failed;
67 packet->additional[0].name = io->in.name;
68 packet->additional[0].rr_type = NBT_QTYPE_NETBIOS;
69 packet->additional[0].rr_class = NBT_QCLASS_IP;
70 packet->additional[0].ttl = io->in.ttl;
71 packet->additional[0].rdata.netbios.length = 6;
72 packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
73 struct nbt_rdata_address, 1);
74 if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
75 packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
76 packet->additional[0].rdata.netbios.addresses[0].ipaddr =
77 talloc_strdup(packet->additional, io->in.address);
78 if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed;
80 dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
81 io->in.dest_addr, io->in.dest_port);
82 if (dest == NULL) goto failed;
83 req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
84 io->in.timeout, io->in.retries, false);
85 if (req == NULL) goto failed;
87 talloc_free(packet);
88 return req;
90 failed:
91 talloc_free(packet);
92 return NULL;
96 wait for a registration reply
98 _PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
99 TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
101 NTSTATUS status;
102 struct nbt_name_packet *packet;
104 status = nbt_name_request_recv(req);
105 if (!NT_STATUS_IS_OK(status) ||
106 req->num_replies == 0) {
107 talloc_free(req);
108 return status;
111 packet = req->replies[0].packet;
112 io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
114 if (packet->ancount != 1 ||
115 packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
116 packet->answers[0].rr_class != NBT_QCLASS_IP) {
117 talloc_free(req);
118 return NT_STATUS_INVALID_NETWORK_RESPONSE;
121 io->out.rcode = packet->operation & NBT_RCODE;
122 io->out.name = packet->answers[0].name;
123 if (packet->answers[0].rdata.netbios.length < 6) {
124 talloc_free(req);
125 return NT_STATUS_INVALID_NETWORK_RESPONSE;
127 io->out.reply_addr = talloc_steal(mem_ctx,
128 packet->answers[0].rdata.netbios.addresses[0].ipaddr);
129 talloc_steal(mem_ctx, io->out.name.name);
130 talloc_steal(mem_ctx, io->out.name.scope);
132 talloc_free(req);
134 return NT_STATUS_OK;
138 synchronous name registration request
140 _PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
141 TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
143 struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
144 return nbt_name_register_recv(req, mem_ctx, io);
149 a 4 step broadcast registration. 3 lots of name registration requests, followed by
150 a name registration demand
152 struct nbt_name_register_bcast_state {
153 struct nbt_name_socket *nbtsock;
154 struct nbt_name_register io;
157 static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq);
160 the async send call for a 4 stage name registration
162 _PUBLIC_ struct tevent_req *nbt_name_register_bcast_send(TALLOC_CTX *mem_ctx,
163 struct tevent_context *ev,
164 struct nbt_name_socket *nbtsock,
165 struct nbt_name_register_bcast *io)
167 struct tevent_req *req;
168 struct nbt_name_register_bcast_state *state;
169 struct nbt_name_request *subreq;
171 req = tevent_req_create(mem_ctx, &state,
172 struct nbt_name_register_bcast_state);
173 if (req == NULL) {
174 return NULL;
177 state->io.in.name = io->in.name;
178 state->io.in.dest_addr = io->in.dest_addr;
179 state->io.in.dest_port = io->in.dest_port;
180 state->io.in.address = io->in.address;
181 state->io.in.nb_flags = io->in.nb_flags;
182 state->io.in.register_demand = false;
183 state->io.in.broadcast = true;
184 state->io.in.multi_homed = false;
185 state->io.in.ttl = io->in.ttl;
186 state->io.in.timeout = 1;
187 state->io.in.retries = 2;
189 state->nbtsock = nbtsock;
191 subreq = nbt_name_register_send(nbtsock, &state->io);
192 if (tevent_req_nomem(subreq, req)) {
193 return tevent_req_post(req, ev);
196 subreq->async.fn = nbt_name_register_bcast_handler;
197 subreq->async.private_data = req;
199 return req;
202 static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq)
204 struct tevent_req *req =
205 talloc_get_type_abort(subreq->async.private_data,
206 struct tevent_req);
207 struct nbt_name_register_bcast_state *state =
208 tevent_req_data(req,
209 struct nbt_name_register_bcast_state);
210 NTSTATUS status;
212 status = nbt_name_register_recv(subreq, state, &state->io);
213 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
214 if (state->io.in.register_demand == true) {
215 tevent_req_done(req);
216 return;
219 /* the registration timed out - good, send the demand */
220 state->io.in.register_demand = true;
221 state->io.in.retries = 0;
223 subreq = nbt_name_register_send(state->nbtsock, &state->io);
224 if (tevent_req_nomem(subreq, req)) {
225 return;
228 subreq->async.fn = nbt_name_register_bcast_handler;
229 subreq->async.private_data = req;
230 return;
233 if (!NT_STATUS_IS_OK(status)) {
234 tevent_req_nterror(req, status);
235 return;
238 DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
239 state->io.out.reply_from,
240 nbt_name_string(state, &state->io.out.name),
241 state->io.out.reply_addr,
242 state->io.out.rcode));
244 tevent_req_nterror(req, NT_STATUS_CONFLICTING_ADDRESSES);
248 broadcast 4 part name register - recv
250 _PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct tevent_req *req)
252 NTSTATUS status;
254 if (tevent_req_is_nterror(req, &status)) {
255 tevent_req_received(req);
256 return status;
259 tevent_req_received(req);
260 return NT_STATUS_OK;
264 broadcast 4 part name register - sync interface
266 NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
267 struct nbt_name_register_bcast *io)
269 TALLOC_CTX *frame = talloc_stackframe();
270 struct tevent_context *ev;
271 struct tevent_req *subreq;
272 NTSTATUS status;
275 * TODO: create a temporary event context
277 ev = nbtsock->event_ctx;
279 subreq = nbt_name_register_bcast_send(frame, ev, nbtsock, io);
280 if (subreq == NULL) {
281 talloc_free(frame);
282 return NT_STATUS_NO_MEMORY;
285 if (!tevent_req_poll(subreq, ev)) {
286 status = map_nt_error_from_unix_common(errno);
287 talloc_free(frame);
288 return status;
291 status = nbt_name_register_bcast_recv(subreq);
292 if (!NT_STATUS_IS_OK(status)) {
293 talloc_free(frame);
294 return status;
297 TALLOC_FREE(frame);
298 return NT_STATUS_OK;
303 a wins name register with multiple WINS servers and multiple
304 addresses to register. Try each WINS server in turn, until we get a
305 reply for each address
307 struct nbt_name_register_wins_state {
308 struct nbt_name_socket *nbtsock;
309 struct nbt_name_register io;
310 char **wins_servers;
311 uint16_t wins_port;
312 char **addresses;
313 uint32_t address_idx;
316 static void nbt_name_register_wins_handler(struct nbt_name_request *subreq);
319 the async send call for a multi-server WINS register
321 _PUBLIC_ struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
322 struct tevent_context *ev,
323 struct nbt_name_socket *nbtsock,
324 struct nbt_name_register_wins *io)
326 struct tevent_req *req;
327 struct nbt_name_register_wins_state *state;
328 struct nbt_name_request *subreq;
330 req = tevent_req_create(mem_ctx, &state,
331 struct nbt_name_register_wins_state);
332 if (req == NULL) {
333 return NULL;
336 if (io->in.wins_servers == NULL) {
337 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
338 return tevent_req_post(req, ev);
341 if (io->in.wins_servers[0] == NULL) {
342 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
343 return tevent_req_post(req, ev);
346 if (io->in.addresses == NULL) {
347 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
348 return tevent_req_post(req, ev);
351 if (io->in.addresses[0] == NULL) {
352 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
353 return tevent_req_post(req, ev);
356 state->wins_port = io->in.wins_port;
357 state->wins_servers = str_list_copy(state, io->in.wins_servers);
358 if (tevent_req_nomem(state->wins_servers, req)) {
359 return tevent_req_post(req, ev);
362 state->addresses = str_list_copy(state, io->in.addresses);
363 if (tevent_req_nomem(state->addresses, req)) {
364 return tevent_req_post(req, ev);
367 state->io.in.name = io->in.name;
368 state->io.in.dest_addr = state->wins_servers[0];
369 state->io.in.dest_port = state->wins_port;
370 state->io.in.address = io->in.addresses[0];
371 state->io.in.nb_flags = io->in.nb_flags;
372 state->io.in.broadcast = false;
373 state->io.in.register_demand = false;
374 state->io.in.multi_homed = (io->in.nb_flags & NBT_NM_GROUP)?false:true;
375 state->io.in.ttl = io->in.ttl;
376 state->io.in.timeout = 3;
377 state->io.in.retries = 2;
379 state->nbtsock = nbtsock;
380 state->address_idx = 0;
382 subreq = nbt_name_register_send(nbtsock, &state->io);
383 if (tevent_req_nomem(subreq, req)) {
384 return tevent_req_post(req, ev);
387 subreq->async.fn = nbt_name_register_wins_handler;
388 subreq->async.private_data = req;
390 return req;
394 state handler for WINS multi-homed multi-server name register
396 static void nbt_name_register_wins_handler(struct nbt_name_request *subreq)
398 struct tevent_req *req =
399 talloc_get_type_abort(subreq->async.private_data,
400 struct tevent_req);
401 struct nbt_name_register_wins_state *state =
402 tevent_req_data(req,
403 struct nbt_name_register_wins_state);
404 NTSTATUS status;
406 status = nbt_name_register_recv(subreq, state, &state->io);
407 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
408 /* the register timed out - try the next WINS server */
409 state->wins_servers++;
410 if (state->wins_servers[0] == NULL) {
411 tevent_req_nterror(req, status);
412 return;
415 state->address_idx = 0;
416 state->io.in.dest_addr = state->wins_servers[0];
417 state->io.in.dest_port = state->wins_port;
418 state->io.in.address = state->addresses[0];
420 subreq = nbt_name_register_send(state->nbtsock, &state->io);
421 if (tevent_req_nomem(subreq, req)) {
422 return;
425 subreq->async.fn = nbt_name_register_wins_handler;
426 subreq->async.private_data = req;
427 return;
430 if (!NT_STATUS_IS_OK(status)) {
431 tevent_req_nterror(req, status);
432 return;
435 if (state->io.out.rcode == 0 &&
436 state->addresses[state->address_idx+1] != NULL) {
437 /* register our next address */
438 state->io.in.address = state->addresses[++(state->address_idx)];
440 subreq = nbt_name_register_send(state->nbtsock, &state->io);
441 if (tevent_req_nomem(subreq, req)) {
442 return;
445 subreq->async.fn = nbt_name_register_wins_handler;
446 subreq->async.private_data = req;
447 return;
450 tevent_req_done(req);
454 multi-homed WINS name register - recv side
456 _PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
457 TALLOC_CTX *mem_ctx,
458 struct nbt_name_register_wins *io)
460 struct nbt_name_register_wins_state *state =
461 tevent_req_data(req,
462 struct nbt_name_register_wins_state);
463 NTSTATUS status;
465 if (tevent_req_is_nterror(req, &status)) {
466 tevent_req_received(req);
467 return status;
470 io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
471 io->out.rcode = state->io.out.rcode;
473 tevent_req_received(req);
474 return NT_STATUS_OK;
478 multi-homed WINS register - sync interface
480 _PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
481 TALLOC_CTX *mem_ctx,
482 struct nbt_name_register_wins *io)
484 TALLOC_CTX *frame = talloc_stackframe();
485 struct tevent_context *ev;
486 struct tevent_req *subreq;
487 NTSTATUS status;
490 * TODO: create a temporary event context
492 ev = nbtsock->event_ctx;
494 subreq = nbt_name_register_wins_send(frame, ev, nbtsock, io);
495 if (subreq == NULL) {
496 talloc_free(frame);
497 return NT_STATUS_NO_MEMORY;
500 if (!tevent_req_poll(subreq, ev)) {
501 status = map_nt_error_from_unix_common(errno);
502 talloc_free(frame);
503 return status;
506 status = nbt_name_register_wins_recv(subreq, mem_ctx, io);
507 if (!NT_STATUS_IS_OK(status)) {
508 talloc_free(frame);
509 return status;
512 TALLOC_FREE(frame);
513 return NT_STATUS_OK;