r5260: - show an error message on nmblookup failure
[samba.git] / source4 / libcli / nbt / nbtsocket.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    low level socket handling for nbt requests
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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "dlinklist.h"
26 #include "libcli/nbt/libnbt.h"
27
28 #define NBT_MAX_PACKET_SIZE 2048
29 #define NBT_MAX_REPLIES 1000
30
31 /*
32   destroy a pending request
33 */
34 static int nbt_name_request_destructor(void *ptr)
35 {
36         struct nbt_name_request *req = talloc_get_type(ptr, struct nbt_name_request);
37         
38         if (req->state == NBT_REQUEST_SEND) {
39                 DLIST_REMOVE(req->nbtsock->send_queue, req);
40         }
41         if (req->state == NBT_REQUEST_WAIT) {
42                 req->nbtsock->num_pending--;
43         }
44         if (req->name_trn_id != 0 && !req->is_reply) {
45                 idr_remove(req->nbtsock->idr, req->name_trn_id);
46                 req->name_trn_id = 0;
47         }
48         if (req->te) {
49                 req->te = NULL;
50         }
51         if (req->nbtsock->send_queue == NULL) {
52                 EVENT_FD_NOT_WRITEABLE(req->nbtsock->fde);
53         }
54         if (req->nbtsock->num_pending == 0 && 
55             req->nbtsock->incoming.handler == NULL) {
56                 EVENT_FD_NOT_READABLE(req->nbtsock->fde);
57         }
58         return 0;
59 }
60
61
62 /*
63   handle send events on a nbt name socket
64 */
65 static void nbt_name_socket_send(struct nbt_name_socket *nbtsock)
66 {
67         struct nbt_name_request *req = nbtsock->send_queue;
68         TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
69         NTSTATUS status;
70
71         while ((req = nbtsock->send_queue)) {
72                 size_t len;
73                 
74                 len = req->encoded.length;
75                 status = socket_sendto(nbtsock->sock, &req->encoded, &len, 0, 
76                                        req->dest_addr, req->dest_port);
77                 if (NT_STATUS_IS_ERR(status)) goto failed;              
78
79                 if (!NT_STATUS_IS_OK(status)) {
80                         talloc_free(tmp_ctx);
81                         return;
82                 }
83
84                 DLIST_REMOVE(nbtsock->send_queue, req);
85                 if (req->is_reply) {
86                         talloc_free(req);
87                 } else {
88                         req->state = NBT_REQUEST_WAIT;
89                         EVENT_FD_READABLE(nbtsock->fde);
90                         nbtsock->num_pending++;
91                 }
92         }
93
94         EVENT_FD_NOT_WRITEABLE(nbtsock->fde);
95         talloc_free(tmp_ctx);
96         return;
97
98 failed:
99         DLIST_REMOVE(nbtsock->send_queue, req);
100         nbt_name_request_destructor(req);
101         req->status = status;
102         req->state = NBT_REQUEST_ERROR;
103         talloc_free(tmp_ctx);
104         if (req->async.fn) {
105                 req->async.fn(req);
106         }
107         return;
108 }
109
110
111 /*
112   handle a request timeout
113 */
114 static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event *te,
115                                     struct timeval t, void *private)
116 {
117         struct nbt_name_request *req = talloc_get_type(private, 
118                                                        struct nbt_name_request);
119
120         if (req->num_retries != 0) {
121                 req->num_retries--;
122                 req->te = event_add_timed(req->nbtsock->event_ctx, req, 
123                                           timeval_add(&t, req->timeout, 0),
124                                           nbt_name_socket_timeout, req);
125                 DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
126                 EVENT_FD_WRITEABLE(req->nbtsock->fde);
127                 return;
128         }
129
130         nbt_name_request_destructor(req);
131         if (req->num_replies == 0) {
132                 req->state = NBT_REQUEST_TIMEOUT;
133                 req->status = NT_STATUS_IO_TIMEOUT;
134         } else {
135                 req->state = NBT_REQUEST_DONE;
136                 req->status = NT_STATUS_OK;
137         }
138         if (req->async.fn) {
139                 req->async.fn(req);
140         }
141 }
142
143
144
145 /*
146   handle recv events on a nbt name socket
147 */
148 static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
149 {
150         TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
151         NTSTATUS status;
152         const char *src_addr;
153         int src_port;
154         DATA_BLOB blob;
155         size_t nread;
156         struct nbt_name_packet *packet;
157         struct nbt_name_request *req;
158
159         blob = data_blob_talloc(tmp_ctx, NULL, NBT_MAX_PACKET_SIZE);
160         if (blob.data == NULL) {
161                 talloc_free(tmp_ctx);
162                 return;
163         }
164
165         status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread, 0,
166                                  &src_addr, &src_port);
167         if (!NT_STATUS_IS_OK(status)) {
168                 talloc_free(tmp_ctx);
169                 return;
170         }
171         talloc_steal(tmp_ctx, src_addr);
172         blob.length = nread;
173
174         packet = talloc(tmp_ctx, struct nbt_name_packet);
175         if (packet == NULL) {
176                 talloc_free(tmp_ctx);
177                 return;
178         }
179
180         /* parse the request */
181         status = ndr_pull_struct_blob(&blob, packet, packet, 
182                                       (ndr_pull_flags_fn_t)ndr_pull_nbt_name_packet);
183         if (!NT_STATUS_IS_OK(status)) {
184                 DEBUG(2,("Failed to parse incoming NBT name packet - %s\n",
185                          nt_errstr(status)));
186                 talloc_free(tmp_ctx);
187                 return;
188         }
189
190         if (DEBUGLVL(10)) {
191                 DEBUG(10,("Received nbt packet of length %d from %s:%d\n", 
192                           blob.length, src_addr, src_port));
193                 NDR_PRINT_DEBUG(nbt_name_packet, packet);
194         }
195
196         /* if its not a reply then pass it off to the incoming request
197            handler, if any */
198         if (!(packet->operation & NBT_FLAG_REPLY)) {
199                 if (nbtsock->incoming.handler) {
200                         nbtsock->incoming.handler(nbtsock, packet, src_addr, src_port);
201                 }
202                 talloc_free(tmp_ctx);
203                 return;
204         }
205
206         /* find the matching request */
207         req = idr_find(nbtsock->idr, packet->name_trn_id);
208         if (req == NULL) {
209                 DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n",
210                          packet->name_trn_id));
211                 talloc_free(tmp_ctx);
212                 return;
213         }
214
215         /* if this is a WACK response, this we need to go back to waiting,
216            but perhaps increase the timeout */
217         if ((packet->operation & NBT_OPCODE) == NBT_OPCODE_WACK) {
218                 if (req->received_wack || packet->ancount < 1) {
219                         nbt_name_request_destructor(req);
220                         req->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
221                         req->state  = NBT_REQUEST_ERROR;
222                         goto done;
223                 }
224                 talloc_free(req->te);
225                 /* we know we won't need any more retries - the server
226                    has received our request */
227                 req->num_retries   = 0;
228                 req->received_wack = True;
229                 if (packet->answers[0].ttl != 0) {
230                         req->timeout       = MIN(packet->answers[0].ttl, 20);
231                 }
232                 req->te            = event_add_timed(req->nbtsock->event_ctx, req, 
233                                                      timeval_current_ofs(req->timeout, 0),
234                                                      nbt_name_socket_timeout, req);
235                 DLIST_ADD_END(req->nbtsock->send_queue, req, struct nbt_name_request *);
236                 EVENT_FD_WRITEABLE(req->nbtsock->fde);
237                 talloc_free(tmp_ctx);
238                 return;
239         }
240         
241
242         req->replies = talloc_realloc(req, req->replies, struct nbt_name_reply, req->num_replies+1);
243         if (req->replies == NULL) {
244                 nbt_name_request_destructor(req);
245                 req->state  = NBT_REQUEST_ERROR;
246                 req->status = NT_STATUS_NO_MEMORY;
247                 goto done;
248         }
249
250         req->replies[req->num_replies].reply_addr = talloc_steal(req, src_addr);
251         req->replies[req->num_replies].reply_port = src_port;
252         req->replies[req->num_replies].packet     = talloc_steal(req, packet);
253         req->num_replies++;
254
255         /* if we don't want multiple replies then we are done */
256         if (req->allow_multiple_replies &&
257             req->num_replies < NBT_MAX_REPLIES) {
258                 talloc_free(tmp_ctx);
259                 return;
260         }
261
262         nbt_name_request_destructor(req);
263         req->state  = NBT_REQUEST_DONE;
264         req->status = NT_STATUS_OK;
265
266 done:
267         talloc_free(tmp_ctx);
268         if (req->async.fn) {
269                 req->async.fn(req);
270         }
271 }
272
273 /*
274   handle fd events on a nbt_name_socket
275 */
276 static void nbt_name_socket_handler(struct event_context *ev, struct fd_event *fde,
277                                     uint16_t flags, void *private)
278 {
279         struct nbt_name_socket *nbtsock = talloc_get_type(private, 
280                                                           struct nbt_name_socket);
281         if (flags & EVENT_FD_WRITE) {
282                 nbt_name_socket_send(nbtsock);
283         } else if (flags & EVENT_FD_READ) {
284                 nbt_name_socket_recv(nbtsock);
285         }
286 }
287
288
289 /*
290   initialise a nbt_name_socket. The event_ctx is optional, if provided
291   then operations will use that event context
292 */
293 struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx, 
294                                              struct event_context *event_ctx)
295 {
296         struct nbt_name_socket *nbtsock;
297         NTSTATUS status;
298
299         nbtsock = talloc(mem_ctx, struct nbt_name_socket);
300         if (nbtsock == NULL) goto failed;
301
302         if (event_ctx == NULL) {
303                 nbtsock->event_ctx = event_context_init(nbtsock);
304         } else {
305                 nbtsock->event_ctx = talloc_reference(nbtsock, event_ctx);
306         }
307         if (nbtsock->event_ctx == NULL) goto failed;
308
309         status = socket_create("ip", SOCKET_TYPE_DGRAM, &nbtsock->sock, 0);
310         if (!NT_STATUS_IS_OK(status)) goto failed;
311
312         socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
313
314         talloc_steal(nbtsock, nbtsock->sock);
315
316         nbtsock->idr = idr_init(nbtsock);
317         if (nbtsock->idr == NULL) goto failed;
318
319         nbtsock->send_queue = NULL;
320         nbtsock->num_pending = 0;
321         nbtsock->incoming.handler = NULL;
322
323         nbtsock->fde = event_add_fd(nbtsock->event_ctx, nbtsock, 
324                                     socket_get_fd(nbtsock->sock), 0,
325                                     nbt_name_socket_handler, nbtsock);
326         
327         return nbtsock;
328
329 failed:
330         talloc_free(nbtsock);
331         return NULL;
332 }
333
334 /*
335   send off a nbt name request
336 */
337 struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock, 
338                                                const char *dest_addr, int dest_port,
339                                                struct nbt_name_packet *request,
340                                                int timeout, int retries,
341                                                BOOL allow_multiple_replies)
342 {
343         struct nbt_name_request *req;
344         int id;
345         NTSTATUS status;
346
347         req = talloc_zero(nbtsock, struct nbt_name_request);
348         if (req == NULL) goto failed;
349
350         req->nbtsock                = nbtsock;
351         req->dest_port              = dest_port;
352         req->allow_multiple_replies = allow_multiple_replies;
353         req->state                  = NBT_REQUEST_SEND;
354         req->is_reply               = False;
355         req->timeout                = timeout;
356         req->num_retries            = retries;
357         req->dest_addr              = talloc_strdup(req, dest_addr);
358         if (req->dest_addr == NULL) goto failed;
359
360         /* we select a random transaction id unless the user supplied one */
361         if (request->name_trn_id == 0) {
362                 request->name_trn_id = generate_random() % UINT16_MAX;
363         }
364
365         /* choose the next available transaction id >= the one asked for.
366            The strange 2nd call is to try to make the ids less guessable
367            and less likely to collide. It's not possible to make NBT secure 
368            to ID guessing, but this at least makes accidential collisions
369            less likely */
370         id = idr_get_new_above(req->nbtsock->idr, req, 
371                                request->name_trn_id, UINT16_MAX);
372         if (id == -1) {
373                 id = idr_get_new_above(req->nbtsock->idr, req, 
374                                        1+(generate_random()%(UINT16_MAX/2)),
375                                        UINT16_MAX);
376         }
377         if (id == -1) goto failed;
378         request->name_trn_id = id;
379         req->name_trn_id     = id;
380
381         req->te = event_add_timed(nbtsock->event_ctx, req, 
382                                   timeval_current_ofs(req->timeout, 0),
383                                   nbt_name_socket_timeout, req);
384         
385         talloc_set_destructor(req, nbt_name_request_destructor);        
386
387         status = ndr_push_struct_blob(&req->encoded, req, request, 
388                                       (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
389         if (!NT_STATUS_IS_OK(status)) goto failed;
390
391         DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
392
393         if (DEBUGLVL(10)) {
394                 DEBUG(10,("Queueing nbt packet to %s:%d\n", 
395                           req->dest_addr, req->dest_port));
396                 NDR_PRINT_DEBUG(nbt_name_packet, request);
397         }
398
399         EVENT_FD_WRITEABLE(nbtsock->fde);
400
401         return req;
402
403 failed:
404         talloc_free(req);
405         return NULL;
406 }
407
408
409 /*
410   send off a nbt name reply
411 */
412 NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock, 
413                              const char *dest_addr, int dest_port,
414                              struct nbt_name_packet *request)
415 {
416         struct nbt_name_request *req;
417         NTSTATUS status;
418
419         req = talloc_zero(nbtsock, struct nbt_name_request);
420         NT_STATUS_HAVE_NO_MEMORY(req);
421
422         req->nbtsock   = nbtsock;
423         req->dest_addr = talloc_strdup(req, dest_addr);
424         if (req->dest_addr == NULL) goto failed;
425         req->dest_port = dest_port;
426         req->state     = NBT_REQUEST_SEND;
427         req->is_reply = True;
428
429         talloc_set_destructor(req, nbt_name_request_destructor);        
430
431         if (DEBUGLVL(10)) {
432                 NDR_PRINT_DEBUG(nbt_name_packet, request);              
433         }
434
435         status = ndr_push_struct_blob(&req->encoded, req, request, 
436                                       (ndr_push_flags_fn_t)ndr_push_nbt_name_packet);
437         if (!NT_STATUS_IS_OK(status)) {
438                 talloc_free(req);
439                 return status;
440         }
441
442         DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
443
444         EVENT_FD_WRITEABLE(nbtsock->fde);
445
446         return NT_STATUS_OK;
447
448 failed:
449         talloc_free(req);
450         return NT_STATUS_NO_MEMORY;
451 }
452
453 /*
454   wait for a nbt request to complete
455 */
456 NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
457 {
458         if (!req) return NT_STATUS_NO_MEMORY;
459
460         while (req->state < NBT_REQUEST_DONE) {
461                 if (event_loop_once(req->nbtsock->event_ctx) != 0) {
462                         req->state = NBT_REQUEST_ERROR;
463                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
464                         if (req->async.fn) {
465                                 req->async.fn(req);
466                         }
467                 }
468         }
469         return req->status;
470 }
471
472
473 /*
474   setup a handler for incoming requests
475 */
476 NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
477                                   void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, 
478                                                   const char *, int ),
479                                   void *private)
480 {
481         nbtsock->incoming.handler = handler;
482         nbtsock->incoming.private = private;
483         EVENT_FD_READABLE(nbtsock->fde);
484         return NT_STATUS_OK;
485 }
486