r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / 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/composite/composite.h"
25 #include "lib/socket/socket.h"
26 #include "librpc/gen_ndr/ndr_nbt.h"
27 #include "param/param.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, lp_nbt_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 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 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, 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 = 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 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.address         = io->in.address;
228         state->io->in.nb_flags        = io->in.nb_flags;
229         state->io->in.register_demand = False;
230         state->io->in.broadcast       = True;
231         state->io->in.multi_homed     = False;
232         state->io->in.ttl             = io->in.ttl;
233         state->io->in.timeout         = 1;
234         state->io->in.retries         = 2;
235
236         state->nbtsock = nbtsock;
237
238         state->req = nbt_name_register_send(nbtsock, state->io);
239         if (state->req == NULL) goto failed;
240
241         state->req->async.fn      = name_register_bcast_handler;
242         state->req->async.private = c;
243
244         c->private_data = state;
245         c->state        = COMPOSITE_STATE_IN_PROGRESS;
246         c->event_ctx    = nbtsock->event_ctx;
247
248         return c;
249
250 failed:
251         talloc_free(c);
252         return NULL;
253 }
254
255 /*
256   broadcast 4 part name register - recv
257 */
258 NTSTATUS nbt_name_register_bcast_recv(struct composite_context *c)
259 {
260         NTSTATUS status;
261         status = composite_wait(c);
262         talloc_free(c);
263         return status;
264 }
265
266 /*
267   broadcast 4 part name register - sync interface
268 */
269 NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
270                                  struct nbt_name_register_bcast *io)
271 {
272         struct composite_context *c = nbt_name_register_bcast_send(nbtsock, io);
273         return nbt_name_register_bcast_recv(c);
274 }
275
276
277 /*
278   a wins name register with multiple WINS servers and multiple
279   addresses to register. Try each WINS server in turn, until we get a
280   reply for each address
281 */
282 struct register_wins_state {
283         struct nbt_name_socket *nbtsock;
284         struct nbt_name_register *io;
285         const char **wins_servers;
286         const char **addresses;
287         int address_idx;
288         struct nbt_name_request *req;
289 };
290
291
292 /*
293   state handler for WINS multi-homed multi-server name register
294 */
295 static void name_register_wins_handler(struct nbt_name_request *req)
296 {
297         struct composite_context *c = talloc_get_type(req->async.private, 
298                                                       struct composite_context);
299         struct register_wins_state *state = talloc_get_type(c->private_data, 
300                                                             struct register_wins_state);
301         NTSTATUS status;
302
303         status = nbt_name_register_recv(state->req, state, state->io);
304         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
305                 /* the register timed out - try the next WINS server */
306                 state->wins_servers++;
307                 state->address_idx = 0;
308                 if (state->wins_servers[0] == NULL) {
309                         c->state = COMPOSITE_STATE_ERROR;
310                         c->status = status;
311                         goto done;
312                 }
313                 state->io->in.dest_addr = state->wins_servers[0];
314                 state->io->in.address   = state->addresses[0];
315                 state->req = nbt_name_register_send(state->nbtsock, state->io);
316                 if (state->req == NULL) {
317                         c->state = COMPOSITE_STATE_ERROR;
318                         c->status = NT_STATUS_NO_MEMORY;
319                 } else {
320                         state->req->async.fn      = name_register_wins_handler;
321                         state->req->async.private = c;
322                 }
323         } else if (!NT_STATUS_IS_OK(status)) {
324                 c->state = COMPOSITE_STATE_ERROR;
325                 c->status = status;
326         } else {
327                 if (state->io->out.rcode == 0 &&
328                     state->addresses[state->address_idx+1] != NULL) {
329                         /* register our next address */
330                         state->io->in.address = state->addresses[++(state->address_idx)];
331                         state->req = nbt_name_register_send(state->nbtsock, state->io);
332                         if (state->req == NULL) {
333                                 c->state = COMPOSITE_STATE_ERROR;
334                                 c->status = NT_STATUS_NO_MEMORY;
335                         } else {
336                                 state->req->async.fn      = name_register_wins_handler;
337                                 state->req->async.private = c;
338                         }
339                 } else {
340                         c->state = COMPOSITE_STATE_DONE;
341                         c->status = NT_STATUS_OK;
342                 }
343         }
344
345 done:
346         if (c->state >= COMPOSITE_STATE_DONE &&
347             c->async.fn) {
348                 c->async.fn(c);
349         }
350 }
351
352 /*
353   the async send call for a multi-server WINS register
354 */
355 struct composite_context *nbt_name_register_wins_send(struct nbt_name_socket *nbtsock,
356                                                       struct nbt_name_register_wins *io)
357 {
358         struct composite_context *c;
359         struct register_wins_state *state;
360
361         c = talloc_zero(nbtsock, struct composite_context);
362         if (c == NULL) goto failed;
363
364         state = talloc(c, struct register_wins_state);
365         if (state == NULL) goto failed;
366
367         state->io = talloc(state, struct nbt_name_register);
368         if (state->io == NULL) goto failed;
369
370         state->wins_servers = str_list_copy(state, io->in.wins_servers);
371         if (state->wins_servers == NULL || 
372             state->wins_servers[0] == NULL) goto failed;
373
374         state->addresses = str_list_copy(state, io->in.addresses);
375         if (state->addresses == NULL || 
376             state->addresses[0] == NULL) goto failed;
377
378         state->io->in.name            = io->in.name;
379         state->io->in.dest_addr       = state->wins_servers[0];
380         state->io->in.address         = io->in.addresses[0];
381         state->io->in.nb_flags        = io->in.nb_flags;
382         state->io->in.broadcast       = False;
383         state->io->in.register_demand = False;
384         state->io->in.multi_homed     = (io->in.nb_flags & NBT_NM_GROUP)?False:True;
385         state->io->in.ttl             = io->in.ttl;
386         state->io->in.timeout         = 3;
387         state->io->in.retries         = 2;
388
389         state->nbtsock     = nbtsock;
390         state->address_idx = 0;
391
392         state->req = nbt_name_register_send(nbtsock, state->io);
393         if (state->req == NULL) goto failed;
394
395         state->req->async.fn      = name_register_wins_handler;
396         state->req->async.private = c;
397
398         c->private_data = state;
399         c->state        = COMPOSITE_STATE_IN_PROGRESS;
400         c->event_ctx    = nbtsock->event_ctx;
401
402         return c;
403
404 failed:
405         talloc_free(c);
406         return NULL;
407 }
408
409 /*
410   multi-homed WINS name register - recv side
411 */
412 NTSTATUS nbt_name_register_wins_recv(struct composite_context *c, TALLOC_CTX *mem_ctx,
413                                      struct nbt_name_register_wins *io)
414 {
415         NTSTATUS status;
416         status = composite_wait(c);
417         if (NT_STATUS_IS_OK(status)) {
418                 struct register_wins_state *state = 
419                         talloc_get_type(c->private_data, struct register_wins_state);
420                 io->out.wins_server = talloc_steal(mem_ctx, state->wins_servers[0]);
421                 io->out.rcode = state->io->out.rcode;
422         }
423         talloc_free(c);
424         return status;
425 }
426
427 /*
428   multi-homed WINS register - sync interface
429 */
430 NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
431                                 TALLOC_CTX *mem_ctx,
432                                 struct nbt_name_register_wins *io)
433 {
434         struct composite_context *c = nbt_name_register_wins_send(nbtsock, io);
435         return nbt_name_register_wins_recv(c, mem_ctx, io);
436 }