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