r5114: the nbtd task can now act as a basic B-node server. It registers its
[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 "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->request->name_trn_id != 0 && 
45             !(req->request->operation & NBT_FLAG_REPLY)) {
46                 idr_remove(req->nbtsock->idr, req->request->name_trn_id);
47                 req->request->name_trn_id = 0;
48         }
49         if (req->te) {
50                 req->te = NULL;
51         }
52         if (req->nbtsock->send_queue == NULL) {
53                 req->nbtsock->fde->flags &= ~EVENT_FD_WRITE;
54         }
55         if (req->nbtsock->num_pending == 0 && 
56             req->nbtsock->incoming.handler == NULL) {
57                 req->nbtsock->fde->flags &= ~EVENT_FD_READ;
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                 DATA_BLOB blob;
74                 size_t len;
75                 
76                 if (DEBUGLVL(10)) {
77                         DEBUG(10,("Sending nbt packet to %s:%d\n", 
78                                   req->dest_addr, req->dest_port));
79                         NDR_PRINT_DEBUG(nbt_name_packet, req->request);
80                 }
81
82                 status = ndr_push_struct_blob(&blob, tmp_ctx, req->request, 
83                                               (ndr_push_flags_fn_t)
84                                               ndr_push_nbt_name_packet);
85                 if (!NT_STATUS_IS_OK(status)) goto failed;
86
87                 if (req->request->operation & NBT_FLAG_BROADCAST) {
88                         socket_set_option(nbtsock->sock, "SO_BROADCAST", "1");
89                 }
90
91                 len = blob.length;
92                 status = socket_sendto(nbtsock->sock, &blob, &len, 0, 
93                                        req->dest_addr, req->dest_port);
94                 if (NT_STATUS_IS_ERR(status)) goto failed;              
95
96                 if (!NT_STATUS_IS_OK(status)) {
97                         talloc_free(tmp_ctx);
98                         return;
99                 }
100
101                 DLIST_REMOVE(nbtsock->send_queue, req);
102                 if (req->request->operation & NBT_FLAG_REPLY) {
103                         talloc_free(req);
104                 } else {
105                         req->state = NBT_REQUEST_WAIT;
106                         nbtsock->fde->flags |= EVENT_FD_READ;
107                         nbtsock->num_pending++;
108                 }
109         }
110
111         nbtsock->fde->flags &= ~EVENT_FD_WRITE;
112         talloc_free(tmp_ctx);
113         return;
114
115 failed:
116         DLIST_REMOVE(nbtsock->send_queue, req);
117         nbt_name_request_destructor(req);
118         req->status = status;
119         req->state = NBT_REQUEST_ERROR;
120         talloc_free(tmp_ctx);
121         if (req->async.fn) {
122                 req->async.fn(req);
123         }
124         return;
125 }
126
127
128 /*
129   handle recv events on a nbt name socket
130 */
131 static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
132 {
133         TALLOC_CTX *tmp_ctx = talloc_new(nbtsock);
134         NTSTATUS status;
135         const char *src_addr;
136         int src_port;
137         DATA_BLOB blob;
138         size_t nread;
139         struct nbt_name_packet *packet;
140         struct nbt_name_request *req;
141
142         blob = data_blob_talloc(tmp_ctx, NULL, NBT_MAX_PACKET_SIZE);
143         if (blob.data == NULL) {
144                 talloc_free(tmp_ctx);
145                 return;
146         }
147
148         status = socket_recvfrom(nbtsock->sock, blob.data, blob.length, &nread, 0,
149                                  &src_addr, &src_port);
150         if (!NT_STATUS_IS_OK(status)) {
151                 talloc_free(tmp_ctx);
152                 return;
153         }
154         talloc_steal(tmp_ctx, src_addr);
155         blob.length = nread;
156
157         packet = talloc(tmp_ctx, struct nbt_name_packet);
158         if (packet == NULL) {
159                 talloc_free(tmp_ctx);
160                 return;
161         }
162
163         status = ndr_pull_struct_blob(&blob, packet, packet, 
164                                       (ndr_pull_flags_fn_t)ndr_pull_nbt_name_packet);
165         if (!NT_STATUS_IS_OK(status)) {
166                 DEBUG(2,("Failed to parse incoming NBT name packet - %s\n",
167                          nt_errstr(status)));
168                 talloc_free(tmp_ctx);
169                 return;
170         }
171
172         if (DEBUGLVL(10)) {
173                 DEBUG(10,("Received nbt packet of length %d from %s:%d\n", 
174                           blob.length, src_addr, src_port));
175                 NDR_PRINT_DEBUG(nbt_name_packet, packet);
176         }
177
178         if (!(packet->operation & NBT_FLAG_REPLY)) {
179                 if (nbtsock->incoming.handler) {
180                         nbtsock->incoming.handler(nbtsock, packet, src_addr, src_port);
181                 }
182                 talloc_free(tmp_ctx);
183                 return;
184         }
185
186         /* find the matching request */
187         req = idr_find(nbtsock->idr, packet->name_trn_id);
188         if (req == NULL) {
189                 DEBUG(2,("Failed to match request for incoming name packet id 0x%04x\n",
190                          packet->name_trn_id));
191                 talloc_free(tmp_ctx);
192                 return;
193         }
194
195         req->replies = talloc_realloc(req, req->replies, struct nbt_name_reply, req->num_replies+1);
196         if (req->replies == NULL) {
197                 nbt_name_request_destructor(req);
198                 req->state = NBT_REQUEST_DONE;
199                 req->status = NT_STATUS_NO_MEMORY;
200                 talloc_free(tmp_ctx);
201                 if (req->async.fn) {
202                         req->async.fn(req);
203                 }
204                 return;
205         }
206
207         req->replies[req->num_replies].reply_addr = talloc_steal(req, src_addr);
208         req->replies[req->num_replies].reply_port = src_port;
209         req->replies[req->num_replies].packet = talloc_steal(req, packet);
210         req->num_replies++;
211
212         talloc_free(tmp_ctx);
213
214         /* if we don't want multiple replies then we are done */
215         if (!req->allow_multiple_replies ||
216             req->num_replies == NBT_MAX_REPLIES) {
217                 nbt_name_request_destructor(req);
218                 req->state = NBT_REQUEST_DONE;
219                 req->status = NT_STATUS_OK;
220                 if (req->async.fn) {
221                         req->async.fn(req);
222                 }
223         }
224 }
225
226 /*
227   handle fd events on a nbt_name_socket
228 */
229 static void nbt_name_socket_handler(struct event_context *ev, struct fd_event *fde,
230                                     struct timeval t, uint16_t flags)
231 {
232         struct nbt_name_socket *nbtsock = talloc_get_type(fde->private, 
233                                                           struct nbt_name_socket);
234         if (flags & EVENT_FD_WRITE) {
235                 nbt_name_socket_send(nbtsock);
236         } else if (flags & EVENT_FD_READ) {
237                 nbt_name_socket_recv(nbtsock);
238         }
239 }
240
241
242 /*
243   initialise a nbt_name_socket. The event_ctx is optional, if provided
244   then operations will use that event context
245 */
246 struct nbt_name_socket *nbt_name_socket_init(TALLOC_CTX *mem_ctx, 
247                                              struct event_context *event_ctx)
248 {
249         struct nbt_name_socket *nbtsock;
250         NTSTATUS status;
251         struct fd_event fde;
252
253         nbtsock = talloc(mem_ctx, struct nbt_name_socket);
254         if (nbtsock == NULL) goto failed;
255
256         if (event_ctx == NULL) {
257                 nbtsock->event_ctx = event_context_init(nbtsock);
258         } else {
259                 nbtsock->event_ctx = talloc_reference(nbtsock, event_ctx);
260         }
261         if (nbtsock->event_ctx == NULL) goto failed;
262
263         status = socket_create("ip", SOCKET_TYPE_DGRAM, &nbtsock->sock, 0);
264         if (!NT_STATUS_IS_OK(status)) goto failed;
265
266         talloc_steal(nbtsock, nbtsock->sock);
267
268         nbtsock->idr = idr_init(nbtsock);
269         if (nbtsock->idr == NULL) goto failed;
270
271         nbtsock->send_queue = NULL;
272         nbtsock->num_pending = 0;
273
274         fde.fd = socket_get_fd(nbtsock->sock);
275         fde.flags = 0;
276         fde.handler = nbt_name_socket_handler;
277         fde.private = nbtsock;
278         nbtsock->fde = event_add_fd(nbtsock->event_ctx, &fde, nbtsock);
279         
280         return nbtsock;
281
282 failed:
283         talloc_free(nbtsock);
284         return NULL;
285 }
286
287 /*
288   handle a request timeout
289 */
290 static void nbt_name_socket_timeout(struct event_context *ev, struct timed_event *te,
291                                     struct timeval t)
292 {
293         struct nbt_name_request *req = talloc_get_type(te->private, 
294                                                        struct nbt_name_request);
295         nbt_name_request_destructor(req);
296         if (req->num_replies == 0) {
297                 req->state = NBT_REQUEST_TIMEOUT;
298                 req->status = NT_STATUS_IO_TIMEOUT;
299         } else {
300                 req->state = NBT_REQUEST_DONE;
301                 req->status = NT_STATUS_OK;
302         }
303         if (req->async.fn) {
304                 req->async.fn(req);
305         }
306 }
307
308 /*
309   send off a nbt name request
310 */
311 struct nbt_name_request *nbt_name_request_send(struct nbt_name_socket *nbtsock, 
312                                                const char *dest_addr, int dest_port,
313                                                struct nbt_name_packet *request,
314                                                struct timeval timeout,
315                                                BOOL allow_multiple_replies)
316 {
317         struct nbt_name_request *req;
318         struct timed_event te;
319         int id;
320
321         req = talloc_zero(nbtsock, struct nbt_name_request);
322         if (req == NULL) goto failed;
323
324         req->nbtsock = nbtsock;
325         req->dest_addr = talloc_strdup(req, dest_addr);
326         if (req->dest_addr == NULL) goto failed;
327         req->dest_port = dest_port;
328         req->request = talloc_reference(req, request);
329         req->allow_multiple_replies = allow_multiple_replies;
330         req->state = NBT_REQUEST_SEND;
331
332         /* we select a random transaction id unless the user supplied one */
333         if (req->request->name_trn_id == 0) {
334                 req->request->name_trn_id = generate_random() % UINT16_MAX;
335         }
336
337         /* choose the next available transaction id >= the one asked for.
338            The strange 2nd call is to try to make the ids less guessable
339            and less likely to collide. It's not possible to make NBT secure 
340            to ID guessing, but this at least makes accidential collisions
341            less likely */
342         id = idr_get_new_above(req->nbtsock->idr, req, 
343                                req->request->name_trn_id, UINT16_MAX);
344         if (id == -1) {
345                 id = idr_get_new_above(req->nbtsock->idr, req, 
346                                        1+(generate_random()%(UINT16_MAX/2)),
347                                        UINT16_MAX);
348         }
349         if (id == -1) goto failed;
350         req->request->name_trn_id = id;
351
352         te.next_event = timeout;
353         te.handler = nbt_name_socket_timeout;
354         te.private = req;
355         req->te = event_add_timed(nbtsock->event_ctx, &te, req);
356         
357         talloc_set_destructor(req, nbt_name_request_destructor);        
358
359         DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
360
361         nbtsock->fde->flags |= EVENT_FD_WRITE;
362
363         return req;
364
365 failed:
366         talloc_free(req);
367         return NULL;
368 }
369
370
371 /*
372   send off a nbt name reply
373 */
374 NTSTATUS nbt_name_reply_send(struct nbt_name_socket *nbtsock, 
375                              const char *dest_addr, int dest_port,
376                              struct nbt_name_packet *request)
377 {
378         struct nbt_name_request *req;
379
380         req = talloc_zero(nbtsock, struct nbt_name_request);
381         NT_STATUS_HAVE_NO_MEMORY(req);
382
383         req->nbtsock   = nbtsock;
384         req->dest_addr = talloc_strdup(req, dest_addr);
385         if (req->dest_addr == NULL) goto failed;
386         req->dest_port = dest_port;
387         req->request   = talloc_reference(req, request);
388         req->state     = NBT_REQUEST_SEND;
389
390         talloc_set_destructor(req, nbt_name_request_destructor);        
391
392         DLIST_ADD_END(nbtsock->send_queue, req, struct nbt_name_request *);
393
394         nbtsock->fde->flags |= EVENT_FD_WRITE;
395
396         return NT_STATUS_OK;
397
398 failed:
399         talloc_free(req);
400         return NT_STATUS_NO_MEMORY;
401 }
402
403 /*
404   wait for a nbt request to complete
405 */
406 NTSTATUS nbt_name_request_recv(struct nbt_name_request *req)
407 {
408         if (!req) return NT_STATUS_NO_MEMORY;
409
410         while (req->state < NBT_REQUEST_DONE) {
411                 if (event_loop_once(req->nbtsock->event_ctx) != 0) {
412                         req->state = NBT_REQUEST_ERROR;
413                         req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
414                         if (req->async.fn) {
415                                 req->async.fn(req);
416                         }
417                 }
418         }
419         return req->status;
420 }
421
422
423 /*
424   setup a handler for incoming requests
425 */
426 NTSTATUS nbt_set_incoming_handler(struct nbt_name_socket *nbtsock,
427                                   void (*handler)(struct nbt_name_socket *, struct nbt_name_packet *, 
428                                                   const char *, int ),
429                                   void *private)
430 {
431         nbtsock->incoming.handler = handler;
432         nbtsock->incoming.private = private;
433         nbtsock->fde->flags |= EVENT_FD_READ;
434         return NT_STATUS_OK;
435 }
436