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