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