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