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