libcli/nbt: fix wack timeout handling
[kai/samba-autobuild/.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 "../libcli/nbt/libnbt.h"
24 #include "../libcli/nbt/nbt_proto.h"
25 #include "libcli/composite/composite.h"
26 #include "lib/socket/socket.h"
27 #include "librpc/gen_ndr/ndr_nbt.h"
28
29 /*
30   send a nbt name registration request
31 */
32 struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
33                                                 struct nbt_name_register *io)
34 {
35         struct nbt_name_request *req;
36         struct nbt_name_packet *packet;
37         struct socket_address *dest;
38
39         packet = talloc_zero(nbtsock, struct nbt_name_packet);
40         if (packet == NULL) return NULL;
41
42         packet->qdcount = 1;
43         packet->arcount = 1;
44         if (io->in.multi_homed) {
45                 packet->operation = NBT_OPCODE_MULTI_HOME_REG;
46         } else {
47                 packet->operation = NBT_OPCODE_REGISTER;
48         }
49         if (io->in.broadcast) {
50                 packet->operation |= NBT_FLAG_BROADCAST;
51         }
52         if (io->in.register_demand) {
53                 packet->operation |= NBT_FLAG_RECURSION_DESIRED;
54         }
55
56         packet->questions = talloc_array(packet, struct nbt_name_question, 1);
57         if (packet->questions == NULL) goto failed;
58
59         packet->questions[0].name           = io->in.name;
60         packet->questions[0].question_type  = NBT_QTYPE_NETBIOS;
61         packet->questions[0].question_class = NBT_QCLASS_IP;
62
63         packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
64         if (packet->additional == NULL) goto failed;
65
66         packet->additional[0].name                   = io->in.name;
67         packet->additional[0].rr_type                = NBT_QTYPE_NETBIOS;
68         packet->additional[0].rr_class               = NBT_QCLASS_IP;
69         packet->additional[0].ttl                    = io->in.ttl;
70         packet->additional[0].rdata.netbios.length   = 6;
71         packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
72                                                                      struct nbt_rdata_address, 1);
73         if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
74         packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
75         packet->additional[0].rdata.netbios.addresses[0].ipaddr =
76                 talloc_strdup(packet->additional, io->in.address);
77         if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed;
78
79         dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
80                                            io->in.dest_addr, io->in.dest_port);
81         if (dest == NULL) goto failed;
82         req = nbt_name_request_send(nbtsock, dest, packet,
83                                     io->in.timeout, io->in.retries, false);
84         if (req == NULL) goto failed;
85
86         talloc_free(packet);
87         return req;
88
89 failed:
90         talloc_free(packet);
91         return NULL;
92 }
93
94 /*
95   wait for a registration reply
96 */
97 _PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
98                                 TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
99 {
100         NTSTATUS status;
101         struct nbt_name_packet *packet;
102
103         status = nbt_name_request_recv(req);
104         if (!NT_STATUS_IS_OK(status) ||
105             req->num_replies == 0) {
106                 talloc_free(req);
107                 return status;
108         }
109
110         packet = req->replies[0].packet;
111         io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
112
113         if (packet->ancount != 1 ||
114             packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
115             packet->answers[0].rr_class != NBT_QCLASS_IP) {
116                 talloc_free(req);
117                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
118         }
119
120         io->out.rcode = packet->operation & NBT_RCODE;
121         io->out.name = packet->answers[0].name;
122         if (packet->answers[0].rdata.netbios.length < 6) {
123                 talloc_free(req);
124                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
125         }
126         io->out.reply_addr = talloc_steal(mem_ctx,
127                                           packet->answers[0].rdata.netbios.addresses[0].ipaddr);
128         talloc_steal(mem_ctx, io->out.name.name);
129         talloc_steal(mem_ctx, io->out.name.scope);
130
131         talloc_free(req);
132
133         return NT_STATUS_OK;
134 }
135
136 /*
137   synchronous name registration request
138 */
139 _PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
140                            TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
141 {
142         struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
143         return nbt_name_register_recv(req, mem_ctx, io);
144 }
145
146
147 /*
148   a 4 step broadcast registration. 3 lots of name registration requests, followed by
149   a name registration demand
150 */
151 struct register_bcast_state {
152         struct nbt_name_socket *nbtsock;
153         struct nbt_name_register *io;
154         struct nbt_name_request *req;
155 };
156
157
158 /*
159   state handler for 4 stage name registration
160 */
161 static void name_register_bcast_handler(struct nbt_name_request *req)
162 {
163         struct composite_context *c = talloc_get_type(req->async.private_data, struct composite_context);
164         struct register_bcast_state *state = talloc_get_type(c->private_data, struct register_bcast_state);
165         NTSTATUS status;
166
167         status = nbt_name_register_recv(state->req, state, state->io);
168         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
169                 if (state->io->in.register_demand == true) {
170                         /* all done */
171                         c->state = COMPOSITE_STATE_DONE;
172                         c->status = NT_STATUS_OK;
173                         goto done;
174                 }
175
176                 /* the registration timed out - good, send the demand */
177                 state->io->in.register_demand = true;
178                 state->io->in.retries         = 0;
179                 state->req = nbt_name_register_send(state->nbtsock, state->io);
180                 if (state->req == NULL) {
181                         c->state = COMPOSITE_STATE_ERROR;
182                         c->status = NT_STATUS_NO_MEMORY;
183                 } else {
184                         state->req->async.fn      = name_register_bcast_handler;
185                         state->req->async.private_data = c;
186                 }
187         } else if (!NT_STATUS_IS_OK(status)) {
188                 c->state = COMPOSITE_STATE_ERROR;
189                 c->status = status;
190         } else {
191                 c->state = COMPOSITE_STATE_ERROR;
192                 c->status = NT_STATUS_CONFLICTING_ADDRESSES;
193                 DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
194                          state->io->out.reply_from,
195                          nbt_name_string(state, &state->io->out.name),
196                          state->io->out.reply_addr,
197                          state->io->out.rcode));
198         }
199
200 done:
201         if (c->state >= COMPOSITE_STATE_DONE &&
202             c->async.fn) {
203                 c->async.fn(c);
204         }
205 }
206
207 /*
208   the async send call for a 4 stage name registration
209 */
210 _PUBLIC_ struct composite_context *nbt_name_register_bcast_send(struct nbt_name_socket *nbtsock,
211                                                        struct nbt_name_register_bcast *io)
212 {
213         struct composite_context *c;
214         struct register_bcast_state *state;
215
216         c = talloc_zero(nbtsock, struct composite_context);
217         if (c == NULL) goto failed;
218
219         state = talloc(c, struct register_bcast_state);
220         if (state == NULL) goto failed;
221
222         state->io = talloc(state, struct nbt_name_register);
223         if (state->io == NULL) goto failed;
224
225         state->io->in.name            = io->in.name;
226         state->io->in.dest_addr       = io->in.dest_addr;
227         state->io->in.dest_port       = io->in.dest_port;
228         state->io->in.address         = io->in.address;
229         state->io->in.nb_flags        = io->in.nb_flags;
230         state->io->in.register_demand = false;
231         state->io->in.broadcast       = true;
232         state->io->in.multi_homed     = false;
233         state->io->in.ttl             = io->in.ttl;
234         state->io->in.timeout         = 1;
235         state->io->in.retries         = 2;
236
237         state->nbtsock = nbtsock;
238
239         state->req = nbt_name_register_send(nbtsock, state->io);
240         if (state->req == NULL) goto failed;
241
242         state->req->async.fn      = name_register_bcast_handler;
243         state->req->async.private_data = c;
244
245         c->private_data = state;
246         c->state        = COMPOSITE_STATE_IN_PROGRESS;
247         c->event_ctx    = nbtsock->event_ctx;
248
249         return c;
250
251 failed:
252         talloc_free(c);
253         return NULL;
254 }
255
256 /*
257   broadcast 4 part name register - recv
258 */
259 _PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c)
260 {
261         NTSTATUS status;
262         status = composite_wait(c);
263         talloc_free(c);
264         return status;
265 }
266
267 /*
268   broadcast 4 part name register - sync interface
269 */
270 NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
271                                  struct nbt_name_register_bcast *io)
272 {
273         struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io);
274         return nbt_name_register_bcast_recv(c);
275 }
276
277
278 /*
279   a wins name register with multiple WINS servers and multiple
280   addresses to register. Try each WINS server in turn, until we get a
281   reply for each address
282 */
283 struct register_wins_state {
284         struct nbt_name_socket *nbtsock;
285         struct nbt_name_register *io;
286         const char **wins_servers;
287         uint16_t wins_port;
288         const char **addresses;
289         int address_idx;
290         struct nbt_name_request *req;
291 };
292
293
294 /*
295   state handler for WINS multi-homed multi-server name register
296 */
297 static void name_register_wins_handler(struct nbt_name_request *req)
298 {
299         struct composite_context *c = talloc_get_type(req->async.private_data,
300                                                       struct composite_context);
301         struct register_wins_state *state = talloc_get_type(c->private_data,
302                                                             struct register_wins_state);
303         NTSTATUS status;
304
305         status = nbt_name_register_recv(state->req, state, state->io);
306         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
307                 /* the register timed out - try the next WINS server */
308                 state->wins_servers++;
309                 state->address_idx = 0;
310                 if (state->wins_servers[0] == NULL) {
311                         c->state = COMPOSITE_STATE_ERROR;
312                         c->status = status;
313                         goto done;
314                 }
315                 state->io->in.dest_addr = state->wins_servers[0];
316                 state->io->in.dest_port = state->wins_port;
317                 state->io->in.address   = state->addresses[0];
318                 state->req = nbt_name_register_send(state->nbtsock, state->io);
319                 if (state->req == NULL) {
320                         c->state = COMPOSITE_STATE_ERROR;
321                         c->status = NT_STATUS_NO_MEMORY;
322                 } else {
323                         state->req->async.fn      = name_register_wins_handler;
324                         state->req->async.private_data = c;
325                 }
326         } else if (!NT_STATUS_IS_OK(status)) {
327                 c->state = COMPOSITE_STATE_ERROR;
328                 c->status = status;
329         } else {
330                 if (state->io->out.rcode == 0 &&
331                     state->addresses[state->address_idx+1] != NULL) {
332                         /* register our next address */
333                         state->io->in.address = state->addresses[++(state->address_idx)];
334                         state->req = nbt_name_register_send(state->nbtsock, state->io);
335                         if (state->req == NULL) {
336                                 c->state = COMPOSITE_STATE_ERROR;
337                                 c->status = NT_STATUS_NO_MEMORY;
338                         } else {
339                                 state->req->async.fn      = name_register_wins_handler;
340                                 state->req->async.private_data = c;
341                         }
342                 } else {
343                         c->state = COMPOSITE_STATE_DONE;
344                         c->status = NT_STATUS_OK;
345                 }
346         }
347
348 done:
349         if (c->state >= COMPOSITE_STATE_DONE &&
350             c->async.fn) {
351                 c->async.fn(c);
352         }
353 }
354
355 /*
356   the async send call for a multi-server WINS register
357 */
358 _PUBLIC_ struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock,
359                                                       struct nbt_name_register_wins *io)
360 {
361         struct composite_context *c;
362         struct register_wins_state *state;
363
364         c = talloc_zero(nbtsock, struct composite_context);
365         if (c == NULL) goto failed;
366
367         state = talloc(c, struct register_wins_state);
368         if (state == NULL) goto failed;
369
370         state->io = talloc(state, struct nbt_name_register);
371         if (state->io == NULL) goto failed;
372
373         state->wins_port = io->in.wins_port;
374         state->wins_servers = (const char **)str_list_copy(state, io->in.wins_servers);
375         if (state->wins_servers == NULL ||
376             state->wins_servers[0] == NULL) goto failed;
377
378         state->addresses = (const char **)str_list_copy(state, io->in.addresses);
379         if (state->addresses == NULL ||
380             state->addresses[0] == NULL) goto failed;
381
382         state->io->in.name            = io->in.name;
383         state->io->in.dest_addr       = state->wins_servers[0];
384         state->io->in.dest_port       = state->wins_port;
385         state->io->in.address         = io->in.addresses[0];
386         state->io->in.nb_flags        = io->in.nb_flags;
387         state->io->in.broadcast       = false;
388         state->io->in.register_demand = false;
389         state->io->in.multi_homed     = (io->in.nb_flags & NBT_NM_GROUP)?false:true;
390         state->io->in.ttl             = io->in.ttl;
391         state->io->in.timeout         = 3;
392         state->io->in.retries         = 2;
393
394         state->nbtsock     = nbtsock;
395         state->address_idx = 0;
396
397         state->req = nbt_name_register_send(nbtsock, state->io);
398         if (state->req == NULL) goto failed;
399
400         state->req->async.fn      = name_register_wins_handler;
401         state->req->async.private_data = c;
402
403         c->private_data = state;
404         c->state        = COMPOSITE_STATE_IN_PROGRESS;
405         c->event_ctx    = nbtsock->event_ctx;
406
407         return c;
408
409 failed:
410         talloc_free(c);
411         return NULL;
412 }
413
414 /*
415   multi-homed WINS name register - recv side
416 */
417 _PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
418                                      struct nbt_name_register_wins *io)
419 {
420         NTSTATUS status;
421         status = composite_wait(c);
422         if (NT_STATUS_IS_OK(status)) {
423                 struct register_wins_state *state =
424                         talloc_get_type(c->private_data, struct register_wins_state);
425                 io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]);
426                 io->out.rcode = state->io->out.rcode;
427         }
428         talloc_free(c);
429         return status;
430 }
431
432 /*
433   multi-homed WINS register - sync interface
434 */
435 _PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
436                                 TALLOC_CTX *mem_ctx,
437                                 struct nbt_name_register_wins *io)
438 {
439         struct composite_context *c = nbt_name_register_wins_send(nbtsock, io);
440         return nbt_name_register_wins_recv(c, mem_ctx, io);
441 }