Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : handle unexpected packets
4 : Copyright (C) Andrew Tridgell 2000
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 :
19 : */
20 :
21 : #include "includes.h"
22 : #include "libsmb/unexpected.h"
23 : #include "../lib/util/tevent_ntstatus.h"
24 : #include "lib/util_tsock.h"
25 : #include "libsmb/nmblib.h"
26 : #include "lib/tsocket/tsocket.h"
27 : #include "lib/util/sys_rw.h"
28 :
29 292 : static const char *nmbd_socket_dir(void)
30 : {
31 292 : return lp_parm_const_string(-1, "nmbd", "socket dir",
32 : get_dyn_NMBDSOCKETDIR());
33 : }
34 :
35 : struct nb_packet_query {
36 : enum packet_type type;
37 : size_t mailslot_namelen;
38 : int trn_id;
39 : };
40 :
41 : struct nb_packet_client;
42 :
43 : struct nb_packet_server {
44 : struct tevent_context *ev;
45 : int listen_sock;
46 : struct tevent_fd *listen_fde;
47 : int max_clients;
48 : int num_clients;
49 : struct nb_packet_client *clients;
50 : };
51 :
52 : struct nb_packet_client {
53 : struct nb_packet_client *prev, *next;
54 : struct nb_packet_server *server;
55 :
56 : enum packet_type type;
57 : int trn_id;
58 : char *mailslot_name;
59 :
60 : struct {
61 : uint8_t byte;
62 : struct iovec iov[1];
63 : } ack;
64 :
65 : struct tstream_context *sock;
66 : struct tevent_queue *out_queue;
67 : };
68 :
69 : static int nb_packet_server_destructor(struct nb_packet_server *s);
70 : static void nb_packet_server_listener(struct tevent_context *ev,
71 : struct tevent_fd *fde,
72 : uint16_t flags,
73 : void *private_data);
74 :
75 23 : NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
76 : struct tevent_context *ev,
77 : int max_clients,
78 : struct nb_packet_server **presult)
79 : {
80 : struct nb_packet_server *result;
81 : NTSTATUS status;
82 : int rc;
83 :
84 23 : result = talloc_zero(mem_ctx, struct nb_packet_server);
85 23 : if (result == NULL) {
86 0 : status = NT_STATUS_NO_MEMORY;
87 0 : goto fail;
88 : }
89 23 : result->ev = ev;
90 23 : result->max_clients = max_clients;
91 :
92 23 : result->listen_sock = create_pipe_sock(
93 : nmbd_socket_dir(), "unexpected", 0755);
94 23 : if (result->listen_sock == -1) {
95 0 : status = map_nt_error_from_unix(errno);
96 0 : goto fail;
97 : }
98 23 : rc = listen(result->listen_sock, 5);
99 23 : if (rc < 0) {
100 0 : status = map_nt_error_from_unix(errno);
101 0 : goto fail;
102 : }
103 23 : talloc_set_destructor(result, nb_packet_server_destructor);
104 :
105 23 : result->listen_fde = tevent_add_fd(ev, result,
106 : result->listen_sock,
107 : TEVENT_FD_READ,
108 : nb_packet_server_listener,
109 : result);
110 23 : if (result->listen_fde == NULL) {
111 0 : status = NT_STATUS_NO_MEMORY;
112 0 : goto fail;
113 : }
114 :
115 23 : *presult = result;
116 23 : return NT_STATUS_OK;
117 0 : fail:
118 0 : TALLOC_FREE(result);
119 0 : return status;
120 : }
121 :
122 0 : static int nb_packet_server_destructor(struct nb_packet_server *s)
123 : {
124 0 : TALLOC_FREE(s->listen_fde);
125 :
126 0 : if (s->listen_sock != -1) {
127 0 : close(s->listen_sock);
128 0 : s->listen_sock = -1;
129 : }
130 0 : return 0;
131 : }
132 :
133 : static int nb_packet_client_destructor(struct nb_packet_client *c);
134 : static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
135 : void *private_data);
136 : static void nb_packet_got_query(struct tevent_req *req);
137 : static void nb_packet_client_ack_done(struct tevent_req *req);
138 : static void nb_packet_client_read_done(struct tevent_req *req);
139 :
140 375 : static void nb_packet_server_listener(struct tevent_context *ev,
141 : struct tevent_fd *fde,
142 : uint16_t flags,
143 : void *private_data)
144 : {
145 375 : struct nb_packet_server *server = talloc_get_type_abort(
146 : private_data, struct nb_packet_server);
147 : struct nb_packet_client *client;
148 : struct tevent_req *req;
149 : struct sockaddr_un sunaddr;
150 : socklen_t len;
151 : int sock;
152 : int ret;
153 :
154 375 : len = sizeof(sunaddr);
155 :
156 375 : sock = accept(server->listen_sock, (struct sockaddr *)(void *)&sunaddr,
157 : &len);
158 375 : if (sock == -1) {
159 0 : return;
160 : }
161 375 : smb_set_close_on_exec(sock);
162 375 : DEBUG(6,("accepted socket %d\n", sock));
163 :
164 375 : client = talloc_zero(server, struct nb_packet_client);
165 375 : if (client == NULL) {
166 0 : DEBUG(10, ("talloc failed\n"));
167 0 : close(sock);
168 0 : return;
169 : }
170 375 : ret = tstream_bsd_existing_socket(client, sock, &client->sock);
171 375 : if (ret != 0) {
172 0 : DEBUG(10, ("tstream_bsd_existing_socket failed\n"));
173 0 : TALLOC_FREE(client);
174 0 : close(sock);
175 0 : return;
176 : }
177 :
178 375 : client->server = server;
179 :
180 375 : client->out_queue = tevent_queue_create(
181 : client, "unexpected packet output");
182 375 : if (client->out_queue == NULL) {
183 0 : DEBUG(10, ("tevent_queue_create failed\n"));
184 0 : TALLOC_FREE(client);
185 0 : return;
186 : }
187 :
188 375 : req = tstream_read_packet_send(client, ev, client->sock,
189 : sizeof(struct nb_packet_query),
190 : nb_packet_client_more, NULL);
191 375 : if (req == NULL) {
192 0 : DEBUG(10, ("tstream_read_packet_send failed\n"));
193 0 : TALLOC_FREE(client);
194 0 : return;
195 : }
196 375 : tevent_req_set_callback(req, nb_packet_got_query, client);
197 :
198 375 : DLIST_ADD(server->clients, client);
199 375 : server->num_clients += 1;
200 :
201 375 : talloc_set_destructor(client, nb_packet_client_destructor);
202 :
203 375 : if (server->num_clients > server->max_clients) {
204 0 : DEBUG(10, ("Too many clients, dropping oldest\n"));
205 :
206 : /*
207 : * no TALLOC_FREE here, don't mess with the list structs
208 : */
209 0 : talloc_free(server->clients->prev);
210 : }
211 : }
212 :
213 377 : static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
214 : void *private_data)
215 : {
216 : struct nb_packet_query q;
217 377 : if (buflen > sizeof(struct nb_packet_query)) {
218 2 : return 0;
219 : }
220 : /* Take care of alignment */
221 375 : memcpy(&q, buf, sizeof(q));
222 375 : if (q.mailslot_namelen > 1024) {
223 0 : DEBUG(10, ("Got invalid mailslot namelen %d\n",
224 : (int)q.mailslot_namelen));
225 0 : return -1;
226 : }
227 375 : return q.mailslot_namelen;
228 : }
229 :
230 375 : static int nb_packet_client_destructor(struct nb_packet_client *c)
231 : {
232 375 : tevent_queue_stop(c->out_queue);
233 375 : TALLOC_FREE(c->sock);
234 :
235 375 : DLIST_REMOVE(c->server->clients, c);
236 375 : c->server->num_clients -= 1;
237 375 : return 0;
238 : }
239 :
240 375 : static void nb_packet_got_query(struct tevent_req *req)
241 : {
242 375 : struct nb_packet_client *client = tevent_req_callback_data(
243 : req, struct nb_packet_client);
244 : struct nb_packet_query q;
245 : uint8_t *buf;
246 : ssize_t nread;
247 : int err;
248 :
249 375 : nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
250 375 : TALLOC_FREE(req);
251 375 : if (nread < (ssize_t)sizeof(struct nb_packet_query)) {
252 0 : DEBUG(10, ("read_packet_recv returned %d (%s)\n",
253 : (int)nread,
254 : (nread == -1) ? strerror(err) : "wrong length"));
255 0 : TALLOC_FREE(client);
256 0 : return;
257 : }
258 :
259 : /* Take care of alignment */
260 375 : memcpy(&q, buf, sizeof(q));
261 :
262 375 : if ((size_t)nread !=
263 375 : sizeof(struct nb_packet_query) + q.mailslot_namelen) {
264 0 : DEBUG(10, ("nb_packet_got_query: Invalid mailslot namelength\n"));
265 0 : TALLOC_FREE(client);
266 0 : return;
267 : }
268 :
269 375 : client->trn_id = q.trn_id;
270 375 : client->type = q.type;
271 375 : if (q.mailslot_namelen > 0) {
272 4 : client->mailslot_name = talloc_strndup(
273 2 : client, (char *)buf + sizeof(q),
274 : q.mailslot_namelen);
275 2 : if (client->mailslot_name == NULL) {
276 0 : TALLOC_FREE(client);
277 0 : return;
278 : }
279 : }
280 :
281 375 : client->ack.byte = 0;
282 375 : client->ack.iov[0].iov_base = &client->ack.byte;
283 375 : client->ack.iov[0].iov_len = 1;
284 375 : req = tstream_writev_queue_send(client, client->server->ev,
285 : client->sock,
286 : client->out_queue,
287 375 : client->ack.iov, 1);
288 375 : if (req == NULL) {
289 0 : DEBUG(10, ("tstream_writev_queue_send failed\n"));
290 0 : TALLOC_FREE(client);
291 0 : return;
292 : }
293 375 : tevent_req_set_callback(req, nb_packet_client_ack_done, client);
294 :
295 375 : req = tstream_read_packet_send(client, client->server->ev,
296 : client->sock, 1, NULL, NULL);
297 375 : if (req == NULL) {
298 0 : DEBUG(10, ("Could not activate reader for client exit "
299 : "detection\n"));
300 0 : TALLOC_FREE(client);
301 0 : return;
302 : }
303 375 : tevent_req_set_callback(req, nb_packet_client_read_done,
304 : client);
305 : }
306 :
307 375 : static void nb_packet_client_ack_done(struct tevent_req *req)
308 : {
309 375 : struct nb_packet_client *client = tevent_req_callback_data(
310 : req, struct nb_packet_client);
311 : ssize_t nwritten;
312 : int err;
313 :
314 375 : nwritten = tstream_writev_queue_recv(req, &err);
315 :
316 375 : TALLOC_FREE(req);
317 :
318 375 : if (nwritten == -1) {
319 0 : DEBUG(10, ("tstream_writev_queue_recv failed: %s\n",
320 : strerror(err)));
321 0 : TALLOC_FREE(client);
322 0 : return;
323 : }
324 : }
325 :
326 375 : static void nb_packet_client_read_done(struct tevent_req *req)
327 : {
328 375 : struct nb_packet_client *client = tevent_req_callback_data(
329 : req, struct nb_packet_client);
330 : ssize_t nread;
331 : uint8_t *buf;
332 : int err;
333 :
334 375 : nread = tstream_read_packet_recv(req, talloc_tos(), &buf, &err);
335 375 : TALLOC_FREE(req);
336 375 : if (nread == 1) {
337 0 : DEBUG(10, ("Protocol error, received data on write-only "
338 : "unexpected socket: 0x%2.2x\n", (*buf)));
339 : }
340 375 : TALLOC_FREE(client);
341 375 : }
342 :
343 : static void nb_packet_client_send(struct nb_packet_client *client,
344 : struct packet_struct *p);
345 :
346 297 : void nb_packet_dispatch(struct nb_packet_server *server,
347 : struct packet_struct *p)
348 : {
349 : struct nb_packet_client *c;
350 : uint16_t trn_id;
351 :
352 297 : switch (p->packet_type) {
353 0 : case NMB_PACKET:
354 0 : trn_id = p->packet.nmb.header.name_trn_id;
355 0 : break;
356 297 : case DGRAM_PACKET:
357 297 : trn_id = p->packet.dgram.header.dgm_id;
358 297 : break;
359 0 : default:
360 0 : DEBUG(10, ("Got invalid packet type %d\n",
361 : (int)p->packet_type));
362 0 : return;
363 : }
364 312 : for (c = server->clients; c != NULL; c = c->next) {
365 :
366 15 : if (c->type != p->packet_type) {
367 13 : DEBUG(10, ("client expects packet %d, got %d\n",
368 : c->type, p->packet_type));
369 13 : continue;
370 : }
371 :
372 2 : if (p->packet_type == NMB_PACKET) {
373 : /*
374 : * See if the client specified transaction
375 : * ID. Filter if it did.
376 : */
377 0 : if ((c->trn_id != -1) &&
378 0 : (c->trn_id != trn_id)) {
379 0 : DEBUG(10, ("client expects trn %d, got %d\n",
380 : c->trn_id, trn_id));
381 0 : continue;
382 : }
383 : } else {
384 : /*
385 : * See if the client specified a mailslot
386 : * name. Filter if it did.
387 : */
388 4 : if ((c->mailslot_name != NULL) &&
389 2 : !match_mailslot_name(p, c->mailslot_name)) {
390 0 : continue;
391 : }
392 : }
393 2 : nb_packet_client_send(c, p);
394 : }
395 : }
396 :
397 : struct nb_packet_client_header {
398 : size_t len;
399 : enum packet_type type;
400 : time_t timestamp;
401 : struct in_addr ip;
402 : int port;
403 : };
404 :
405 : struct nb_packet_client_state {
406 : struct nb_packet_client *client;
407 : struct iovec iov[2];
408 : struct nb_packet_client_header hdr;
409 : char buf[1024];
410 : };
411 :
412 : static void nb_packet_client_send_done(struct tevent_req *req);
413 :
414 2 : static void nb_packet_client_send(struct nb_packet_client *client,
415 : struct packet_struct *p)
416 : {
417 : struct nb_packet_client_state *state;
418 : struct tevent_req *req;
419 :
420 2 : if (tevent_queue_length(client->out_queue) > 10) {
421 : /*
422 : * Skip clients that don't listen anyway, some form of DoS
423 : * protection
424 : */
425 0 : return;
426 : }
427 :
428 2 : state = talloc_zero(client, struct nb_packet_client_state);
429 2 : if (state == NULL) {
430 0 : DEBUG(10, ("talloc failed\n"));
431 0 : return;
432 : }
433 :
434 2 : state->client = client;
435 :
436 2 : state->hdr.ip = p->ip;
437 2 : state->hdr.port = p->port;
438 2 : state->hdr.timestamp = p->timestamp;
439 2 : state->hdr.type = p->packet_type;
440 2 : state->hdr.len = build_packet(state->buf, sizeof(state->buf), p);
441 :
442 2 : state->iov[0].iov_base = (char *)&state->hdr;
443 2 : state->iov[0].iov_len = sizeof(state->hdr);
444 2 : state->iov[1].iov_base = state->buf;
445 2 : state->iov[1].iov_len = state->hdr.len;
446 :
447 2 : req = tstream_writev_queue_send(state, client->server->ev,
448 : client->sock,
449 : client->out_queue,
450 2 : state->iov, 2);
451 2 : if (req == NULL) {
452 0 : DEBUG(10, ("tstream_writev_queue_send failed\n"));
453 0 : return;
454 : }
455 2 : tevent_req_set_callback(req, nb_packet_client_send_done, state);
456 : }
457 :
458 2 : static void nb_packet_client_send_done(struct tevent_req *req)
459 : {
460 2 : struct nb_packet_client_state *state = tevent_req_callback_data(
461 : req, struct nb_packet_client_state);
462 2 : struct nb_packet_client *client = state->client;
463 : ssize_t nwritten;
464 : int err;
465 :
466 2 : nwritten = tstream_writev_queue_recv(req, &err);
467 :
468 2 : TALLOC_FREE(req);
469 2 : TALLOC_FREE(state);
470 :
471 2 : if (nwritten == -1) {
472 0 : DEBUG(10, ("tstream_writev_queue failed: %s\n", strerror(err)));
473 0 : TALLOC_FREE(client);
474 0 : return;
475 : }
476 : }
477 :
478 : struct nb_packet_reader {
479 : struct tstream_context *sock;
480 : };
481 :
482 : struct nb_packet_reader_state {
483 : struct tevent_context *ev;
484 : struct nb_packet_query query;
485 : const char *mailslot_name;
486 : struct iovec iov[2];
487 : struct nb_packet_reader *reader;
488 : };
489 :
490 : static void nb_packet_reader_connected(struct tevent_req *subreq);
491 : static void nb_packet_reader_sent_query(struct tevent_req *subreq);
492 : static void nb_packet_reader_got_ack(struct tevent_req *subreq);
493 :
494 269 : struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
495 : struct tevent_context *ev,
496 : enum packet_type type,
497 : int trn_id,
498 : const char *mailslot_name)
499 : {
500 : struct tevent_req *req, *subreq;
501 : struct nb_packet_reader_state *state;
502 : struct tsocket_address *laddr;
503 : char *rpath;
504 : struct tsocket_address *raddr;
505 : int ret;
506 :
507 269 : req = tevent_req_create(mem_ctx, &state,
508 : struct nb_packet_reader_state);
509 269 : if (req == NULL) {
510 0 : return NULL;
511 : }
512 269 : state->ev = ev;
513 269 : state->query.trn_id = trn_id;
514 269 : state->query.type = type;
515 269 : state->mailslot_name = mailslot_name;
516 :
517 269 : if (mailslot_name != NULL) {
518 1 : state->query.mailslot_namelen = strlen(mailslot_name);
519 : }
520 :
521 269 : state->reader = talloc_zero(state, struct nb_packet_reader);
522 269 : if (tevent_req_nomem(state->reader, req)) {
523 0 : return tevent_req_post(req, ev);
524 : }
525 :
526 269 : ret = tsocket_address_unix_from_path(state, NULL, &laddr);
527 269 : if (ret != 0) {
528 0 : tevent_req_nterror(req, map_nt_error_from_unix(errno));
529 0 : return tevent_req_post(req, ev);
530 : }
531 269 : rpath = talloc_asprintf(state, "%s/%s", nmbd_socket_dir(),
532 : "unexpected");
533 269 : if (tevent_req_nomem(rpath, req)) {
534 0 : return tevent_req_post(req, ev);
535 : }
536 269 : ret = tsocket_address_unix_from_path(state, rpath, &raddr);
537 269 : if (ret != 0) {
538 0 : tevent_req_nterror(req, map_nt_error_from_unix(errno));
539 0 : return tevent_req_post(req, ev);
540 : }
541 :
542 269 : subreq = tstream_unix_connect_send(state, ev, laddr, raddr);
543 269 : if (tevent_req_nomem(subreq, req)) {
544 0 : return tevent_req_post(req, ev);
545 : }
546 269 : tevent_req_set_callback(subreq, nb_packet_reader_connected, req);
547 269 : return req;
548 : }
549 :
550 269 : static void nb_packet_reader_connected(struct tevent_req *subreq)
551 : {
552 269 : struct tevent_req *req = tevent_req_callback_data(
553 : subreq, struct tevent_req);
554 269 : struct nb_packet_reader_state *state = tevent_req_data(
555 : req, struct nb_packet_reader_state);
556 : int res, err;
557 269 : int num_iovecs = 1;
558 :
559 269 : res = tstream_unix_connect_recv(subreq, &err, state->reader,
560 : &state->reader->sock);
561 269 : TALLOC_FREE(subreq);
562 269 : if (res == -1) {
563 99 : DEBUG(10, ("tstream_unix_connect failed: %s\n", strerror(err)));
564 99 : tevent_req_nterror(req, map_nt_error_from_unix(err));
565 99 : return;
566 : }
567 :
568 170 : state->iov[0].iov_base = (char *)&state->query;
569 170 : state->iov[0].iov_len = sizeof(state->query);
570 :
571 170 : if (state->mailslot_name != NULL) {
572 1 : num_iovecs = 2;
573 1 : state->iov[1].iov_base = discard_const_p(
574 : char, state->mailslot_name);
575 1 : state->iov[1].iov_len = state->query.mailslot_namelen;
576 : }
577 :
578 280 : subreq = tstream_writev_send(state, state->ev, state->reader->sock,
579 170 : state->iov, num_iovecs);
580 170 : if (tevent_req_nomem(subreq, req)) {
581 0 : return;
582 : }
583 170 : tevent_req_set_callback(subreq, nb_packet_reader_sent_query, req);
584 : }
585 :
586 170 : static void nb_packet_reader_sent_query(struct tevent_req *subreq)
587 : {
588 170 : struct tevent_req *req = tevent_req_callback_data(
589 : subreq, struct tevent_req);
590 170 : struct nb_packet_reader_state *state = tevent_req_data(
591 : req, struct nb_packet_reader_state);
592 : ssize_t written;
593 : int err;
594 :
595 170 : written = tstream_writev_recv(subreq, &err);
596 170 : TALLOC_FREE(subreq);
597 170 : if (written == -1) {
598 0 : tevent_req_nterror(req, map_nt_error_from_unix(err));
599 0 : return;
600 : }
601 170 : if ((size_t)written !=
602 170 : sizeof(state->query) + state->query.mailslot_namelen) {
603 0 : tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
604 0 : return;
605 : }
606 170 : subreq = tstream_read_packet_send(state, state->ev,
607 170 : state->reader->sock,
608 : 1, NULL, NULL);
609 170 : if (tevent_req_nomem(subreq, req)) {
610 0 : return;
611 : }
612 170 : tevent_req_set_callback(subreq, nb_packet_reader_got_ack, req);
613 : }
614 :
615 170 : static void nb_packet_reader_got_ack(struct tevent_req *subreq)
616 : {
617 170 : struct tevent_req *req = tevent_req_callback_data(
618 : subreq, struct tevent_req);
619 170 : struct nb_packet_reader_state *state = tevent_req_data(
620 : req, struct nb_packet_reader_state);
621 : ssize_t nread;
622 : int err;
623 : uint8_t *buf;
624 :
625 170 : nread = tstream_read_packet_recv(subreq, state, &buf, &err);
626 170 : TALLOC_FREE(subreq);
627 170 : if (nread == -1) {
628 0 : DEBUG(10, ("read_packet_recv returned %s\n",
629 : strerror(err)));
630 0 : tevent_req_nterror(req, map_nt_error_from_unix(err));
631 0 : return;
632 : }
633 170 : if (nread != 1) {
634 0 : DBG_DEBUG("read = %zd, expected 1\n", nread);
635 0 : tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
636 0 : return;
637 : }
638 170 : tevent_req_done(req);
639 : }
640 :
641 269 : NTSTATUS nb_packet_reader_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
642 : struct nb_packet_reader **preader)
643 : {
644 269 : struct nb_packet_reader_state *state = tevent_req_data(
645 : req, struct nb_packet_reader_state);
646 : NTSTATUS status;
647 :
648 269 : if (tevent_req_is_nterror(req, &status)) {
649 99 : tevent_req_received(req);
650 99 : return status;
651 : }
652 170 : *preader = talloc_move(mem_ctx, &state->reader);
653 170 : tevent_req_received(req);
654 170 : return NT_STATUS_OK;
655 : }
656 :
657 : struct nb_packet_read_state {
658 : struct nb_packet_client_header hdr;
659 : uint8_t *buf;
660 : size_t buflen;
661 : };
662 :
663 : static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p);
664 : static void nb_packet_read_done(struct tevent_req *subreq);
665 :
666 170 : struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
667 : struct tevent_context *ev,
668 : struct nb_packet_reader *reader)
669 : {
670 : struct tevent_req *req, *subreq;
671 : struct nb_packet_read_state *state;
672 :
673 170 : req = tevent_req_create(mem_ctx, &state, struct nb_packet_read_state);
674 170 : if (req == NULL) {
675 0 : return NULL;
676 : }
677 170 : subreq = tstream_read_packet_send(state, ev, reader->sock,
678 : sizeof(struct nb_packet_client_header),
679 : nb_packet_read_more, state);
680 170 : if (tevent_req_nomem(subreq, req)) {
681 0 : return tevent_req_post(req, ev);
682 : }
683 170 : tevent_req_set_callback(subreq, nb_packet_read_done, req);
684 170 : return req;
685 : }
686 :
687 2 : static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p)
688 : {
689 2 : struct nb_packet_read_state *state = talloc_get_type_abort(
690 : p, struct nb_packet_read_state);
691 :
692 2 : if (buflen > sizeof(struct nb_packet_client_header)) {
693 : /*
694 : * Been here, done
695 : */
696 1 : return 0;
697 : }
698 1 : memcpy(&state->hdr, buf, sizeof(struct nb_packet_client_header));
699 1 : return state->hdr.len;
700 : }
701 :
702 1 : static void nb_packet_read_done(struct tevent_req *subreq)
703 : {
704 1 : struct tevent_req *req = tevent_req_callback_data(
705 : subreq, struct tevent_req);
706 1 : struct nb_packet_read_state *state = tevent_req_data(
707 : req, struct nb_packet_read_state);
708 : ssize_t nread;
709 : int err;
710 :
711 1 : nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
712 1 : if (nread == -1) {
713 0 : tevent_req_nterror(req, map_nt_error_from_unix(err));
714 0 : return;
715 : }
716 1 : state->buflen = nread;
717 1 : tevent_req_done(req);
718 : }
719 :
720 1 : NTSTATUS nb_packet_read_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
721 : struct packet_struct **ppacket)
722 : {
723 1 : struct nb_packet_read_state *state = tevent_req_data(
724 : req, struct nb_packet_read_state);
725 : struct nb_packet_client_header hdr;
726 : struct packet_struct *packet;
727 : NTSTATUS status;
728 :
729 1 : if (tevent_req_is_nterror(req, &status)) {
730 0 : tevent_req_received(req);
731 0 : return status;
732 : }
733 :
734 1 : memcpy(&hdr, state->buf, sizeof(hdr));
735 :
736 3 : packet = parse_packet_talloc(
737 : mem_ctx,
738 1 : (char *)state->buf + sizeof(struct nb_packet_client_header),
739 1 : state->buflen - sizeof(struct nb_packet_client_header),
740 : state->hdr.type, state->hdr.ip, state->hdr.port);
741 1 : if (packet == NULL) {
742 0 : tevent_req_received(req);
743 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
744 : }
745 :
746 1 : *ppacket = packet;
747 1 : tevent_req_received(req);
748 1 : return NT_STATUS_OK;
749 : }
|