libcli/nbt: s/register_bcast_state/nbt_name_register_bcast_state/
[kai/samba.git] / libcli / nbt / nameregister.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    send out a name registration request
5
6    Copyright (C) Andrew Tridgell 2005
7
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.
12
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.
17
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/>.
20 */
21
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"
30
31 /*
32   send a nbt name registration request
33 */
34 struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
35                                                 struct nbt_name_register *io)
36 {
37         struct nbt_name_request *req;
38         struct nbt_name_packet *packet;
39         struct socket_address *dest;
40
41         packet = talloc_zero(nbtsock, struct nbt_name_packet);
42         if (packet == NULL) return NULL;
43
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;
50         }
51         if (io->in.broadcast) {
52                 packet->operation |= NBT_FLAG_BROADCAST;
53         }
54         if (io->in.register_demand) {
55                 packet->operation |= NBT_FLAG_RECURSION_DESIRED;
56         }
57
58         packet->questions = talloc_array(packet, struct nbt_name_question, 1);
59         if (packet->questions == NULL) goto failed;
60
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;
64
65         packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
66         if (packet->additional == NULL) goto failed;
67
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;
80
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;
87
88         talloc_free(packet);
89         return req;
90
91 failed:
92         talloc_free(packet);
93         return NULL;
94 }
95
96 /*
97   wait for a registration reply
98 */
99 _PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
100                                 TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
101 {
102         NTSTATUS status;
103         struct nbt_name_packet *packet;
104
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;
110         }
111
112         packet = req->replies[0].packet;
113         io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
114
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;
120         }
121
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;
127         }
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);
132
133         talloc_free(req);
134
135         return NT_STATUS_OK;
136 }
137
138 /*
139   synchronous name registration request
140 */
141 _PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
142                            TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
143 {
144         struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
145         return nbt_name_register_recv(req, mem_ctx, io);
146 }
147
148
149 /*
150   a 4 step broadcast registration. 3 lots of name registration requests, followed by
151   a name registration demand
152 */
153 struct nbt_name_register_bcast_state {
154         struct nbt_name_socket *nbtsock;
155         struct nbt_name_register *io;
156         struct nbt_name_request *req;
157 };
158
159 static void name_register_bcast_handler(struct nbt_name_request *req);
160
161 /*
162   the async send call for a 4 stage name registration
163 */
164 _PUBLIC_ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *nbtsock,
165                                                                struct nbt_name_register_bcast *io)
166 {
167         struct composite_context *c;
168         struct nbt_name_register_bcast_state *state;
169
170         c = talloc_zero(nbtsock, struct composite_context);
171         if (c == NULL) goto failed;
172
173         state = talloc(c, struct nbt_name_register_bcast_state);
174         if (state == NULL) goto failed;
175
176         state->io = talloc(state, struct nbt_name_register);
177         if (state->io == NULL) goto failed;
178
179         state->io->in.name            = io->in.name;
180         state->io->in.dest_addr       = io->in.dest_addr;
181         state->io->in.dest_port       = io->in.dest_port;
182         state->io->in.address         = io->in.address;
183         state->io->in.nb_flags        = io->in.nb_flags;
184         state->io->in.register_demand = false;
185         state->io->in.broadcast       = true;
186         state->io->in.multi_homed     = false;
187         state->io->in.ttl             = io->in.ttl;
188         state->io->in.timeout         = 1;
189         state->io->in.retries         = 2;
190
191         state->nbtsock = nbtsock;
192
193         state->req = nbt_name_register_send(nbtsock, state->io);
194         if (state->req == NULL) goto failed;
195
196         state->req->async.fn      = name_register_bcast_handler;
197         state->req->async.private_data = c;
198
199         c->private_data = state;
200         c->state        = COMPOSITE_STATE_IN_PROGRESS;
201         c->event_ctx    = nbtsock->event_ctx;
202
203         return c;
204
205 failed:
206         talloc_free(c);
207         return NULL;
208 }
209
210
211 /*
212   state handler for 4 stage name registration
213 */
214 static void name_register_bcast_handler(struct nbt_name_request *req)
215 {
216         struct composite_context *c = talloc_get_type(req->async.private_data, struct composite_context);
217         struct nbt_name_register_bcast_state *state = talloc_get_type(c->private_data, struct nbt_name_register_bcast_state);
218         NTSTATUS status;
219
220         status = nbt_name_register_recv(state->req, state, state->io);
221         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
222                 if (state->io->in.register_demand == true) {
223                         /* all done */
224                         c->state = COMPOSITE_STATE_DONE;
225                         c->status = NT_STATUS_OK;
226                         goto done;
227                 }
228
229                 /* the registration timed out - good, send the demand */
230                 state->io->in.register_demand = true;
231                 state->io->in.retries         = 0;
232                 state->req = nbt_name_register_send(state->nbtsock, state->io);
233                 if (state->req == NULL) {
234                         c->state = COMPOSITE_STATE_ERROR;
235                         c->status = NT_STATUS_NO_MEMORY;
236                 } else {
237                         state->req->async.fn      = name_register_bcast_handler;
238                         state->req->async.private_data = c;
239                 }
240         } else if (!NT_STATUS_IS_OK(status)) {
241                 c->state = COMPOSITE_STATE_ERROR;
242                 c->status = status;
243         } else {
244                 c->state = COMPOSITE_STATE_ERROR;
245                 c->status = NT_STATUS_CONFLICTING_ADDRESSES;
246                 DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
247                          state->io->out.reply_from,
248                          nbt_name_string(state, &state->io->out.name),
249                          state->io->out.reply_addr,
250                          state->io->out.rcode));
251         }
252
253 done:
254         if (c->state >= COMPOSITE_STATE_DONE &&
255             c->async.fn) {
256                 c->async.fn(c);
257         }
258 }
259
260 /*
261   broadcast 4 part name register - recv
262 */
263 _PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c)
264 {
265         NTSTATUS status;
266         status = composite_wait(c);
267         talloc_free(c);
268         return status;
269 }
270
271 /*
272   broadcast 4 part name register - sync interface
273 */
274 NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
275                                  struct nbt_name_register_bcast *io)
276 {
277         struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io);
278         return nbt_name_register_bcast_recv(c);
279 }
280
281
282 /*
283   a wins name register with multiple WINS servers and multiple
284   addresses to register. Try each WINS server in turn, until we get a
285   reply for each address
286 */
287 struct nbt_name_register_wins_state {
288         struct nbt_name_socket *nbtsock;
289         struct nbt_name_register io;
290         char **wins_servers;
291         uint16_t wins_port;
292         char **addresses;
293         uint32_t address_idx;
294 };
295
296 static void nbt_name_register_wins_handler(struct nbt_name_request *subreq);
297
298 /*
299   the async send call for a multi-server WINS register
300 */
301 _PUBLIC_ struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
302                                                 struct tevent_context *ev,
303                                                 struct nbt_name_socket *nbtsock,
304                                                 struct nbt_name_register_wins *io)
305 {
306         struct tevent_req *req;
307         struct nbt_name_register_wins_state *state;
308         struct nbt_name_request *subreq;
309
310         req = tevent_req_create(mem_ctx, &state,
311                                 struct nbt_name_register_wins_state);
312         if (req == NULL) {
313                 return NULL;
314         }
315
316         if (io->in.wins_servers == NULL) {
317                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
318                 return tevent_req_post(req, ev);
319         }
320
321         if (io->in.wins_servers[0] == NULL) {
322                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
323                 return tevent_req_post(req, ev);
324         }
325
326         if (io->in.addresses == NULL) {
327                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
328                 return tevent_req_post(req, ev);
329         }
330
331         if (io->in.addresses[0] == NULL) {
332                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
333                 return tevent_req_post(req, ev);
334         }
335
336         state->wins_port = io->in.wins_port;
337         state->wins_servers = str_list_copy(state, io->in.wins_servers);
338         if (tevent_req_nomem(state->wins_servers, req)) {
339                 return tevent_req_post(req, ev);
340         }
341
342         state->addresses = str_list_copy(state, io->in.addresses);
343         if (tevent_req_nomem(state->addresses, req)) {
344                 return tevent_req_post(req, ev);
345         }
346
347         state->io.in.name            = io->in.name;
348         state->io.in.dest_addr       = state->wins_servers[0];
349         state->io.in.dest_port       = state->wins_port;
350         state->io.in.address         = io->in.addresses[0];
351         state->io.in.nb_flags        = io->in.nb_flags;
352         state->io.in.broadcast       = false;
353         state->io.in.register_demand = false;
354         state->io.in.multi_homed     = (io->in.nb_flags & NBT_NM_GROUP)?false:true;
355         state->io.in.ttl             = io->in.ttl;
356         state->io.in.timeout         = 3;
357         state->io.in.retries         = 2;
358
359         state->nbtsock     = nbtsock;
360         state->address_idx = 0;
361
362         subreq = nbt_name_register_send(nbtsock, &state->io);
363         if (tevent_req_nomem(subreq, req)) {
364                 return tevent_req_post(req, ev);
365         }
366
367         subreq->async.fn = nbt_name_register_wins_handler;
368         subreq->async.private_data = req;
369
370         return req;
371 }
372
373 /*
374   state handler for WINS multi-homed multi-server name register
375 */
376 static void nbt_name_register_wins_handler(struct nbt_name_request *subreq)
377 {
378         struct tevent_req *req =
379                 talloc_get_type_abort(subreq->async.private_data,
380                 struct tevent_req);
381         struct nbt_name_register_wins_state *state =
382                 tevent_req_data(req,
383                 struct nbt_name_register_wins_state);
384         NTSTATUS status;
385
386         status = nbt_name_register_recv(subreq, state, &state->io);
387         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
388                 /* the register timed out - try the next WINS server */
389                 state->wins_servers++;
390                 if (state->wins_servers[0] == NULL) {
391                         tevent_req_nterror(req, status);
392                         return;
393                 }
394
395                 state->address_idx = 0;
396                 state->io.in.dest_addr = state->wins_servers[0];
397                 state->io.in.dest_port = state->wins_port;
398                 state->io.in.address   = state->addresses[0];
399
400                 subreq = nbt_name_register_send(state->nbtsock, &state->io);
401                 if (tevent_req_nomem(subreq, req)) {
402                         return;
403                 }
404
405                 subreq->async.fn = nbt_name_register_wins_handler;
406                 subreq->async.private_data = req;
407                 return;
408         }
409
410         if (!NT_STATUS_IS_OK(status)) {
411                 tevent_req_nterror(req, status);
412                 return;
413         }
414
415         if (state->io.out.rcode == 0 &&
416             state->addresses[state->address_idx+1] != NULL) {
417                 /* register our next address */
418                 state->io.in.address = state->addresses[++(state->address_idx)];
419
420                 subreq = nbt_name_register_send(state->nbtsock, &state->io);
421                 if (tevent_req_nomem(subreq, req)) {
422                         return;
423                 }
424
425                 subreq->async.fn = nbt_name_register_wins_handler;
426                 subreq->async.private_data = req;
427                 return;
428         }
429
430         tevent_req_done(req);
431 }
432
433 /*
434   multi-homed WINS name register - recv side
435 */
436 _PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
437                                               TALLOC_CTX *mem_ctx,
438                                               struct nbt_name_register_wins *io)
439 {
440         struct nbt_name_register_wins_state *state =
441                 tevent_req_data(req,
442                 struct nbt_name_register_wins_state);
443         NTSTATUS status;
444
445         if (tevent_req_is_nterror(req, &status)) {
446                 tevent_req_received(req);
447                 return status;
448         }
449
450         io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
451         io->out.rcode = state->io.out.rcode;
452
453         tevent_req_received(req);
454         return NT_STATUS_OK;
455 }
456
457 /*
458   multi-homed WINS register - sync interface
459 */
460 _PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
461                                 TALLOC_CTX *mem_ctx,
462                                 struct nbt_name_register_wins *io)
463 {
464         TALLOC_CTX *frame = talloc_stackframe();
465         struct tevent_context *ev;
466         struct tevent_req *subreq;
467         NTSTATUS status;
468
469         /*
470          * TODO: create a temporary event context
471          */
472         ev = nbtsock->event_ctx;
473
474         subreq = nbt_name_register_wins_send(frame, ev, nbtsock, io);
475         if (subreq == NULL) {
476                 talloc_free(frame);
477                 return NT_STATUS_NO_MEMORY;
478         }
479
480         if (!tevent_req_poll(subreq, ev)) {
481                 status = map_nt_error_from_unix(errno);
482                 talloc_free(frame);
483                 return status;
484         }
485
486         status = nbt_name_register_wins_recv(subreq, mem_ctx, io);
487         if (!NT_STATUS_IS_OK(status)) {
488                 talloc_free(frame);
489                 return status;
490         }
491
492         TALLOC_FREE(frame);
493         return NT_STATUS_OK;
494 }