s3: Limit the number of unexpected clients to 200
[Samba.git] / source3 / libsmb / unexpected.c
blob4543ffe7c65d20a177292b296341abe3ae74a9bd
1 /*
2 Unix SMB/CIFS implementation.
3 handle unexpected packets
4 Copyright (C) Andrew Tridgell 2000
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.
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.
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/>.
21 #include "includes.h"
22 #include "lib/async_req/async_sock.h"
24 static struct tdb_wrap *tdbd = NULL;
26 /* the key type used in the unexpected packet database */
27 struct unexpected_key {
28 enum packet_type packet_type;
29 time_t timestamp;
30 int count;
33 struct pending_unexpected {
34 struct pending_unexpected *prev, *next;
35 enum packet_type packet_type;
36 int id;
37 time_t timeout;
40 static struct pending_unexpected *pu_list;
42 /****************************************************************************
43 This function is called when nmbd has received an unexpected packet.
44 It checks against the list of outstanding packet transaction id's
45 to see if it should be stored in the unexpected.tdb.
46 **************************************************************************/
48 static struct pending_unexpected *find_unexpected_packet(struct packet_struct *p)
50 struct pending_unexpected *pu;
52 if (!p) {
53 return NULL;
56 for (pu = pu_list; pu; pu = pu->next) {
57 if (pu->packet_type == p->packet_type) {
58 int id = (p->packet_type == DGRAM_PACKET) ?
59 p->packet.dgram.header.dgm_id :
60 p->packet.nmb.header.name_trn_id;
61 if (id == pu->id) {
62 DEBUG(10,("find_unexpected_packet: found packet "
63 "with id = %d\n", pu->id ));
64 return pu;
69 return NULL;
73 /****************************************************************************
74 This function is called when nmbd has been given a packet to send out.
75 It stores a list of outstanding packet transaction id's and the timeout
76 when they should be removed.
77 **************************************************************************/
79 bool store_outstanding_send_packet(struct packet_struct *p)
81 struct pending_unexpected *pu = NULL;
83 if (!p) {
84 return false;
87 pu = find_unexpected_packet(p);
88 if (pu) {
89 /* This is a resend, and we haven't received a
90 reply yet ! Ignore it. */
91 return false;
94 pu = SMB_MALLOC_P(struct pending_unexpected);
95 if (!pu || !p) {
96 return false;
99 ZERO_STRUCTP(pu);
100 pu->packet_type = p->packet_type;
101 pu->id = (p->packet_type == DGRAM_PACKET) ?
102 p->packet.dgram.header.dgm_id :
103 p->packet.nmb.header.name_trn_id;
104 pu->timeout = time(NULL) + 15;
106 DLIST_ADD_END(pu_list, pu, struct pending_unexpected *);
108 DEBUG(10,("store_outstanding_unexpected_packet: storing packet "
109 "with id = %d\n", pu->id ));
111 return true;
114 /****************************************************************************
115 Return true if this is a reply to a packet we were requested to send.
116 **************************************************************************/
118 bool is_requested_send_packet(struct packet_struct *p)
120 return (find_unexpected_packet(p) != NULL);
123 /****************************************************************************
124 This function is called when nmbd has received an unexpected packet.
125 It checks against the list of outstanding packet transaction id's
126 to see if it should be stored in the unexpected.tdb. Don't store if
127 not found.
128 **************************************************************************/
130 static bool should_store_unexpected_packet(struct packet_struct *p)
132 struct pending_unexpected *pu = find_unexpected_packet(p);
134 if (!pu) {
135 return false;
138 /* Remove the outstanding entry. */
139 DLIST_REMOVE(pu_list, pu);
140 SAFE_FREE(pu);
141 return true;
144 /****************************************************************************
145 All unexpected packets are passed in here, to be stored in a unexpected
146 packet database. This allows nmblookup and other tools to receive packets
147 erroneously sent to the wrong port by broken MS systems.
148 **************************************************************************/
150 void unexpected_packet(struct packet_struct *p)
152 static int count;
153 TDB_DATA kbuf, dbuf;
154 struct unexpected_key key;
155 char buf[1024];
156 int len=0;
157 uint32_t enc_ip;
159 if (!should_store_unexpected_packet(p)) {
160 DEBUG(10,("Not storing unexpected packet\n"));
161 return;
164 DEBUG(10,("unexpected_packet: storing packet\n"));
166 if (!tdbd) {
167 tdbd = tdb_wrap_open(NULL, lock_path("unexpected.tdb"), 0,
168 TDB_CLEAR_IF_FIRST|TDB_DEFAULT|TDB_INCOMPATIBLE_HASH,
169 O_RDWR | O_CREAT, 0644);
170 if (!tdbd) {
171 DEBUG(0,("Failed to open unexpected.tdb\n"));
172 return;
176 memset(buf,'\0',sizeof(buf));
178 /* Encode the ip addr and port. */
179 enc_ip = ntohl(p->ip.s_addr);
180 SIVAL(buf,0,enc_ip);
181 SSVAL(buf,4,p->port);
183 len = build_packet(&buf[6], sizeof(buf)-6, p) + 6;
185 ZERO_STRUCT(key); /* needed for potential alignment */
187 key.packet_type = p->packet_type;
188 key.timestamp = p->timestamp;
189 key.count = count++;
191 kbuf.dptr = (uint8_t *)&key;
192 kbuf.dsize = sizeof(key);
193 dbuf.dptr = (uint8_t *)buf;
194 dbuf.dsize = len;
196 tdb_store(tdbd->tdb, kbuf, dbuf, TDB_REPLACE);
200 static time_t lastt;
202 /****************************************************************************
203 Delete the record if it is too old.
204 **************************************************************************/
206 static int traverse_fn(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
208 struct unexpected_key key;
210 if (kbuf.dsize != sizeof(key)) {
211 tdb_delete(ttdb, kbuf);
214 memcpy(&key, kbuf.dptr, sizeof(key));
216 if (lastt - key.timestamp > NMBD_UNEXPECTED_TIMEOUT) {
217 tdb_delete(ttdb, kbuf);
220 return 0;
224 /****************************************************************************
225 Delete all old unexpected packets.
226 **************************************************************************/
228 void clear_unexpected(time_t t)
230 struct pending_unexpected *pu, *pu_next;
232 for (pu = pu_list; pu; pu = pu_next) {
233 pu_next = pu->next;
234 if (pu->timeout < t) {
235 DLIST_REMOVE(pu_list, pu);
236 SAFE_FREE(pu);
240 if (!tdbd) return;
242 if ((lastt != 0) && (t < lastt + NMBD_UNEXPECTED_TIMEOUT))
243 return;
245 lastt = t;
247 tdb_traverse(tdbd->tdb, traverse_fn, NULL);
250 struct receive_unexpected_state {
251 struct packet_struct *matched_packet;
252 int match_id;
253 enum packet_type match_type;
254 const char *match_name;
257 /****************************************************************************
258 tdb traversal fn to find a matching 137 packet.
259 **************************************************************************/
261 static int traverse_match(TDB_CONTEXT *ttdb, TDB_DATA kbuf, TDB_DATA dbuf,
262 void *private_data)
264 struct receive_unexpected_state *state =
265 (struct receive_unexpected_state *)private_data;
266 struct unexpected_key key;
267 struct in_addr ip;
268 uint32_t enc_ip;
269 int port;
270 struct packet_struct *p;
272 if (kbuf.dsize != sizeof(key)) {
273 return 0;
276 memcpy(&key, kbuf.dptr, sizeof(key));
278 if (key.packet_type != state->match_type) return 0;
280 if (dbuf.dsize < 6) {
281 return 0;
284 /* Decode the ip addr and port. */
285 enc_ip = IVAL(dbuf.dptr,0);
286 ip.s_addr = htonl(enc_ip);
287 port = SVAL(dbuf.dptr,4);
289 p = parse_packet((char *)&dbuf.dptr[6],
290 dbuf.dsize-6,
291 state->match_type,
293 port);
294 if (!p)
295 return 0;
297 if ((state->match_type == NMB_PACKET &&
298 p->packet.nmb.header.name_trn_id == state->match_id) ||
299 (state->match_type == DGRAM_PACKET &&
300 match_mailslot_name(p, state->match_name) &&
301 p->packet.dgram.header.dgm_id == state->match_id)) {
302 state->matched_packet = p;
303 tdb_delete(ttdb, kbuf);
304 return -1;
307 free_packet(p);
309 return 0;
312 /****************************************************************************
313 Check for a particular packet in the unexpected packet queue.
314 **************************************************************************/
316 struct packet_struct *receive_unexpected(enum packet_type packet_type, int id,
317 const char *mailslot_name)
319 struct tdb_wrap *tdb2;
320 struct receive_unexpected_state state;
322 tdb2 = tdb_wrap_open(talloc_tos(), lock_path("unexpected.tdb"), 0, 0,
323 O_RDWR, 0);
324 if (!tdb2) return NULL;
326 state.matched_packet = NULL;
327 state.match_id = id;
328 state.match_type = packet_type;
329 state.match_name = mailslot_name;
331 tdb_traverse(tdb2->tdb, traverse_match, &state);
333 TALLOC_FREE(tdb2);
335 return state.matched_packet;
338 static const char *nmbd_socket_dir(void)
340 return lp_parm_const_string(-1, "nmbd", "socket dir", "/tmp/.nmbd");
343 struct nb_packet_query {
344 enum packet_type type;
345 size_t mailslot_namelen;
346 int trn_id;
349 struct nb_packet_client;
351 struct nb_packet_server {
352 struct tevent_context *ev;
353 int listen_sock;
354 int max_clients;
355 int num_clients;
356 struct nb_packet_client *clients;
359 struct nb_packet_client {
360 struct nb_packet_client *prev, *next;
361 struct nb_packet_server *server;
363 enum packet_type type;
364 int trn_id;
365 char *mailslot_name;
367 int sock;
368 struct tevent_req *read_req;
369 struct tevent_queue *out_queue;
372 static int nb_packet_server_destructor(struct nb_packet_server *s);
373 static void nb_packet_server_listener(struct tevent_context *ev,
374 struct tevent_fd *fde,
375 uint16_t flags,
376 void *private_data);
378 NTSTATUS nb_packet_server_create(TALLOC_CTX *mem_ctx,
379 struct tevent_context *ev,
380 int max_clients,
381 struct nb_packet_server **presult)
383 struct nb_packet_server *result;
384 struct tevent_fd *fde;
385 NTSTATUS status;
387 result = TALLOC_ZERO_P(mem_ctx, struct nb_packet_server);
388 if (result == NULL) {
389 status = NT_STATUS_NO_MEMORY;
390 goto fail;
392 result->ev = ev;
393 result->max_clients = max_clients;
395 result->listen_sock = create_pipe_sock(
396 nmbd_socket_dir(), "unexpected", 0755);
397 if (result->listen_sock == -1) {
398 status = map_nt_error_from_unix(errno);
399 goto fail;
401 talloc_set_destructor(result, nb_packet_server_destructor);
403 fde = tevent_add_fd(ev, result, result->listen_sock, TEVENT_FD_READ,
404 nb_packet_server_listener, result);
405 if (fde == NULL) {
406 status = NT_STATUS_NO_MEMORY;
407 goto fail;
410 *presult = result;
411 return NT_STATUS_OK;
412 fail:
413 TALLOC_FREE(result);
414 return status;
417 static int nb_packet_server_destructor(struct nb_packet_server *s)
419 if (s->listen_sock != -1) {
420 close(s->listen_sock);
421 s->listen_sock = -1;
423 return 0;
426 static int nb_packet_client_destructor(struct nb_packet_client *c);
427 static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
428 void *private_data);
429 static void nb_packet_got_query(struct tevent_req *req);
430 static void nb_packet_client_read_done(struct tevent_req *req);
432 static void nb_packet_server_listener(struct tevent_context *ev,
433 struct tevent_fd *fde,
434 uint16_t flags,
435 void *private_data)
437 struct nb_packet_server *server = talloc_get_type_abort(
438 private_data, struct nb_packet_server);
439 struct nb_packet_client *client;
440 struct tevent_req *req;
441 struct sockaddr_un sunaddr;
442 socklen_t len;
443 int sock;
445 len = sizeof(sunaddr);
447 sock = accept(server->listen_sock, (struct sockaddr *)(void *)&sunaddr,
448 &len);
449 if (sock == -1) {
450 return;
452 DEBUG(6,("accepted socket %d\n", sock));
454 client = TALLOC_ZERO_P(server, struct nb_packet_client);
455 if (client == NULL) {
456 DEBUG(10, ("talloc failed\n"));
457 close(sock);
458 return;
460 client->sock = sock;
461 client->server = server;
462 talloc_set_destructor(client, nb_packet_client_destructor);
464 client->out_queue = tevent_queue_create(
465 client, "unexpected packet output");
466 if (client->out_queue == NULL) {
467 DEBUG(10, ("tevent_queue_create failed\n"));
468 TALLOC_FREE(client);
469 return;
472 req = read_packet_send(client, ev, client->sock,
473 sizeof(struct nb_packet_query),
474 nb_packet_client_more, NULL);
475 if (req == NULL) {
476 DEBUG(10, ("read_packet_send failed\n"));
477 TALLOC_FREE(client);
478 return;
480 tevent_req_set_callback(req, nb_packet_got_query, client);
482 DLIST_ADD(server->clients, client);
483 server->num_clients += 1;
485 if (server->num_clients > server->max_clients) {
486 DEBUG(10, ("Too many clients, dropping oldest\n"));
489 * no TALLOC_FREE here, don't mess with the list structs
491 talloc_free(server->clients->prev);
495 static ssize_t nb_packet_client_more(uint8_t *buf, size_t buflen,
496 void *private_data)
498 struct nb_packet_query q;
499 if (buflen > sizeof(struct nb_packet_query)) {
500 return 0;
502 /* Take care of alignment */
503 memcpy(&q, buf, sizeof(q));
504 if (q.mailslot_namelen > 1024) {
505 DEBUG(10, ("Got invalid mailslot namelen %d\n",
506 (int)q.mailslot_namelen));
507 return -1;
509 return q.mailslot_namelen;
512 static int nb_packet_client_destructor(struct nb_packet_client *c)
514 if (c->sock != -1) {
515 close(c->sock);
516 c->sock = -1;
518 DLIST_REMOVE(c->server->clients, c);
519 c->server->num_clients -= 1;
520 return 0;
523 static void nb_packet_got_query(struct tevent_req *req)
525 struct nb_packet_client *client = tevent_req_callback_data(
526 req, struct nb_packet_client);
527 struct nb_packet_query q;
528 uint8_t *buf;
529 ssize_t nread, nwritten;
530 int err;
531 char c;
533 nread = read_packet_recv(req, talloc_tos(), &buf, &err);
534 TALLOC_FREE(req);
535 if (nread < sizeof(struct nb_packet_query)) {
536 DEBUG(10, ("read_packet_recv returned %d (%s)\n",
537 (int)nread,
538 (nread == -1) ? strerror(err) : "wrong length"));
539 TALLOC_FREE(client);
540 return;
543 /* Take care of alignment */
544 memcpy(&q, buf, sizeof(q));
546 if (nread != sizeof(struct nb_packet_query) + q.mailslot_namelen) {
547 DEBUG(10, ("nb_packet_got_query: Invalid mailslot namelength\n"));
548 TALLOC_FREE(client);
549 return;
552 client->trn_id = q.trn_id;
553 client->type = q.type;
554 if (q.mailslot_namelen > 0) {
555 client->mailslot_name = talloc_strndup(
556 client, (char *)buf + sizeof(q),
557 q.mailslot_namelen);
558 if (client->mailslot_name == NULL) {
559 TALLOC_FREE(client);
560 return;
565 * Yes, this is a blocking write of 1 byte into a unix
566 * domain socket that has never been written to. Highly
567 * unlikely that this actually blocks.
569 c = 0;
570 nwritten = sys_write(client->sock, &c, sizeof(c));
571 if (nwritten != sizeof(c)) {
572 DEBUG(10, ("Could not write success indicator to client: %s\n",
573 strerror(errno)));
574 TALLOC_FREE(client);
575 return;
578 client->read_req = read_packet_send(client, client->server->ev,
579 client->sock, 1, NULL, NULL);
580 if (client->read_req == NULL) {
581 DEBUG(10, ("Could not activate reader for client exit "
582 "detection\n"));
583 TALLOC_FREE(client);
584 return;
586 tevent_req_set_callback(client->read_req, nb_packet_client_read_done,
587 client);
590 static void nb_packet_client_read_done(struct tevent_req *req)
592 struct nb_packet_client *client = tevent_req_callback_data(
593 req, struct nb_packet_client);
594 ssize_t nread;
595 uint8_t *buf;
596 int err;
598 nread = read_packet_recv(req, talloc_tos(), &buf, &err);
599 TALLOC_FREE(req);
600 if (nread == 1) {
601 DEBUG(10, ("Protocol error, received data on write-only "
602 "unexpected socket: 0x%2.2x\n", (*buf)));
604 TALLOC_FREE(client);
607 static void nb_packet_client_send(struct nb_packet_client *client,
608 struct packet_struct *p);
610 void nb_packet_dispatch(struct nb_packet_server *server,
611 struct packet_struct *p)
613 struct nb_packet_client *c;
614 uint16_t trn_id;
616 switch (p->packet_type) {
617 case NMB_PACKET:
618 trn_id = p->packet.nmb.header.name_trn_id;
619 break;
620 case DGRAM_PACKET:
621 trn_id = p->packet.dgram.header.dgm_id;
622 break;
623 default:
624 DEBUG(10, ("Got invalid packet type %d\n",
625 (int)p->packet_type));
626 return;
628 for (c = server->clients; c != NULL; c = c->next) {
630 if (c->type != p->packet_type) {
631 DEBUG(10, ("client expects packet %d, got %d\n",
632 c->type, p->packet_type));
633 continue;
636 if (p->packet_type == NMB_PACKET) {
638 * See if the client specified transaction
639 * ID. Filter if it did.
641 if ((c->trn_id != -1) &&
642 (c->trn_id != trn_id)) {
643 DEBUG(10, ("client expects trn %d, got %d\n",
644 c->trn_id, trn_id));
645 continue;
647 } else {
649 * See if the client specified a mailslot
650 * name. Filter if it did.
652 if ((c->mailslot_name != NULL) &&
653 !match_mailslot_name(p, c->mailslot_name)) {
654 continue;
657 nb_packet_client_send(c, p);
661 struct nb_packet_client_header {
662 size_t len;
663 enum packet_type type;
664 time_t timestamp;
665 struct in_addr ip;
666 int port;
669 struct nb_packet_client_state {
670 struct nb_packet_client *client;
671 struct iovec iov[2];
672 struct nb_packet_client_header hdr;
673 char buf[1024];
676 static void nb_packet_client_send_done(struct tevent_req *req);
678 static void nb_packet_client_send(struct nb_packet_client *client,
679 struct packet_struct *p)
681 struct nb_packet_client_state *state;
682 struct tevent_req *req;
684 if (tevent_queue_length(client->out_queue) > 10) {
686 * Skip clients that don't listen anyway, some form of DoS
687 * protection
689 return;
692 state = TALLOC_ZERO_P(client, struct nb_packet_client_state);
693 if (state == NULL) {
694 DEBUG(10, ("talloc failed\n"));
695 return;
698 state->client = client;
700 state->hdr.ip = p->ip;
701 state->hdr.port = p->port;
702 state->hdr.timestamp = p->timestamp;
703 state->hdr.type = p->packet_type;
704 state->hdr.len = build_packet(state->buf, sizeof(state->buf), p);
706 state->iov[0].iov_base = &state->hdr;
707 state->iov[0].iov_len = sizeof(state->hdr);
708 state->iov[1].iov_base = state->buf;
709 state->iov[1].iov_len = state->hdr.len;
711 TALLOC_FREE(client->read_req);
713 req = writev_send(client, client->server->ev, client->out_queue,
714 client->sock, true, state->iov, 2);
715 if (req == NULL) {
716 DEBUG(10, ("writev_send failed\n"));
717 return;
719 tevent_req_set_callback(req, nb_packet_client_send_done, state);
722 static void nb_packet_client_send_done(struct tevent_req *req)
724 struct nb_packet_client_state *state = tevent_req_callback_data(
725 req, struct nb_packet_client_state);
726 struct nb_packet_client *client = state->client;
727 ssize_t nwritten;
728 int err;
730 nwritten = writev_recv(req, &err);
732 TALLOC_FREE(req);
733 TALLOC_FREE(state);
735 if (nwritten == -1) {
736 DEBUG(10, ("writev failed: %s\n", strerror(err)));
737 TALLOC_FREE(client);
740 if (tevent_queue_length(client->out_queue) == 0) {
741 client->read_req = read_packet_send(client, client->server->ev,
742 client->sock, 1,
743 NULL, NULL);
744 if (client->read_req == NULL) {
745 DEBUG(10, ("Could not activate reader for client exit "
746 "detection\n"));
747 TALLOC_FREE(client);
748 return;
750 tevent_req_set_callback(client->read_req,
751 nb_packet_client_read_done,
752 client);
756 struct nb_packet_reader {
757 int sock;
760 struct nb_packet_reader_state {
761 struct tevent_context *ev;
762 struct sockaddr_un addr;
763 struct nb_packet_query query;
764 const char *mailslot_name;
765 struct iovec iov[2];
766 char c;
767 struct nb_packet_reader *reader;
770 static int nb_packet_reader_destructor(struct nb_packet_reader *r);
771 static void nb_packet_reader_connected(struct tevent_req *subreq);
772 static void nb_packet_reader_sent_query(struct tevent_req *subreq);
773 static void nb_packet_reader_got_ack(struct tevent_req *subreq);
775 struct tevent_req *nb_packet_reader_send(TALLOC_CTX *mem_ctx,
776 struct tevent_context *ev,
777 enum packet_type type,
778 int trn_id,
779 const char *mailslot_name)
781 struct tevent_req *req, *subreq;
782 struct nb_packet_reader_state *state;
783 char *path;
785 req = tevent_req_create(mem_ctx, &state,
786 struct nb_packet_reader_state);
787 if (req == NULL) {
788 return NULL;
790 state->ev = ev;
791 state->query.trn_id = trn_id;
792 state->query.type = type;
793 state->mailslot_name = mailslot_name;
795 if (mailslot_name != NULL) {
796 state->query.mailslot_namelen = strlen(mailslot_name);
799 state->reader = TALLOC_ZERO_P(state, struct nb_packet_reader);
800 if (tevent_req_nomem(state->reader, req)) {
801 return tevent_req_post(req, ev);
804 path = talloc_asprintf(talloc_tos(), "%s/%s", nmbd_socket_dir(),
805 "unexpected");
806 if (tevent_req_nomem(path, req)) {
807 return tevent_req_post(req, ev);
809 state->addr.sun_family = AF_UNIX;
810 strlcpy(state->addr.sun_path, path, sizeof(state->addr.sun_path));
811 TALLOC_FREE(path);
813 state->reader->sock = socket(AF_UNIX, SOCK_STREAM, 0);
814 if (state->reader->sock == -1) {
815 tevent_req_nterror(req, map_nt_error_from_unix(errno));
816 return tevent_req_post(req, ev);
818 talloc_set_destructor(state->reader, nb_packet_reader_destructor);
820 subreq = async_connect_send(state, ev, state->reader->sock,
821 (struct sockaddr *)(void *)&state->addr,
822 sizeof(state->addr));
823 if (tevent_req_nomem(subreq, req)) {
824 return tevent_req_post(req, ev);
826 tevent_req_set_callback(subreq, nb_packet_reader_connected, req);
827 return req;
830 static int nb_packet_reader_destructor(struct nb_packet_reader *r)
832 if (r->sock != -1) {
833 close(r->sock);
834 r->sock = -1;
836 return 0;
839 static void nb_packet_reader_connected(struct tevent_req *subreq)
841 struct tevent_req *req = tevent_req_callback_data(
842 subreq, struct tevent_req);
843 struct nb_packet_reader_state *state = tevent_req_data(
844 req, struct nb_packet_reader_state);
845 int res, err;
846 int num_iovecs = 1;
848 res = async_connect_recv(subreq, &err);
849 TALLOC_FREE(subreq);
850 if (res == -1) {
851 DEBUG(10, ("async_connect failed: %s\n", strerror(err)));
852 tevent_req_nterror(req, map_nt_error_from_unix(err));
853 return;
856 state->iov[0].iov_base = &state->query;
857 state->iov[0].iov_len = sizeof(state->query);
859 if (state->mailslot_name != NULL) {
860 num_iovecs = 2;
861 state->iov[1].iov_base = discard_const_p(
862 char, state->mailslot_name);
863 state->iov[1].iov_len = state->query.mailslot_namelen;
866 subreq = writev_send(state, state->ev, NULL, state->reader->sock,
867 true, state->iov, num_iovecs);
868 if (tevent_req_nomem(subreq, req)) {
869 return;
871 tevent_req_set_callback(subreq, nb_packet_reader_sent_query, req);
874 static void nb_packet_reader_sent_query(struct tevent_req *subreq)
876 struct tevent_req *req = tevent_req_callback_data(
877 subreq, struct tevent_req);
878 struct nb_packet_reader_state *state = tevent_req_data(
879 req, struct nb_packet_reader_state);
880 ssize_t written;
881 int err;
883 written = writev_recv(subreq, &err);
884 TALLOC_FREE(subreq);
885 if (written == -1) {
886 tevent_req_nterror(req, map_nt_error_from_unix(err));
887 return;
889 if (written != sizeof(state->query) + state->query.mailslot_namelen) {
890 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
891 return;
893 subreq = read_packet_send(state, state->ev, state->reader->sock,
894 sizeof(state->c), NULL, NULL);
895 if (tevent_req_nomem(subreq, req)) {
896 return;
898 tevent_req_set_callback(subreq, nb_packet_reader_got_ack, req);
901 static void nb_packet_reader_got_ack(struct tevent_req *subreq)
903 struct tevent_req *req = tevent_req_callback_data(
904 subreq, struct tevent_req);
905 struct nb_packet_reader_state *state = tevent_req_data(
906 req, struct nb_packet_reader_state);
907 ssize_t nread;
908 int err;
909 uint8_t *buf;
911 nread = read_packet_recv(subreq, state, &buf, &err);
912 TALLOC_FREE(subreq);
913 if (nread == -1) {
914 DEBUG(10, ("read_packet_recv returned %s\n",
915 strerror(err)));
916 tevent_req_nterror(req, map_nt_error_from_unix(err));
917 return;
919 if (nread != sizeof(state->c)) {
920 DEBUG(10, ("read = %d, expected %d\n", (int)nread,
921 (int)sizeof(state->c)));
922 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
923 return;
925 tevent_req_done(req);
928 NTSTATUS nb_packet_reader_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
929 struct nb_packet_reader **preader)
931 struct nb_packet_reader_state *state = tevent_req_data(
932 req, struct nb_packet_reader_state);
933 NTSTATUS status;
935 if (tevent_req_is_nterror(req, &status)) {
936 return status;
938 *preader = talloc_move(mem_ctx, &state->reader);
939 return NT_STATUS_OK;
942 struct nb_packet_read_state {
943 struct nb_packet_client_header hdr;
944 uint8_t *buf;
945 size_t buflen;
948 static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p);
949 static void nb_packet_read_done(struct tevent_req *subreq);
951 struct tevent_req *nb_packet_read_send(TALLOC_CTX *mem_ctx,
952 struct tevent_context *ev,
953 struct nb_packet_reader *reader)
955 struct tevent_req *req, *subreq;
956 struct nb_packet_read_state *state;
958 req = tevent_req_create(mem_ctx, &state, struct nb_packet_read_state);
959 if (req == NULL) {
960 return NULL;
962 subreq = read_packet_send(state, ev, reader->sock,
963 sizeof(struct nb_packet_client_header),
964 nb_packet_read_more, state);
965 if (tevent_req_nomem(subreq, req)) {
966 return tevent_req_post(req, ev);
968 tevent_req_set_callback(subreq, nb_packet_read_done, req);
969 return req;
972 static ssize_t nb_packet_read_more(uint8_t *buf, size_t buflen, void *p)
974 struct nb_packet_read_state *state = talloc_get_type_abort(
975 p, struct nb_packet_read_state);
977 if (buflen > sizeof(struct nb_packet_client_header)) {
979 * Been here, done
981 return 0;
983 memcpy(&state->hdr, buf, sizeof(struct nb_packet_client_header));
984 return state->hdr.len;
987 static void nb_packet_read_done(struct tevent_req *subreq)
989 struct tevent_req *req = tevent_req_callback_data(
990 subreq, struct tevent_req);
991 struct nb_packet_read_state *state = tevent_req_data(
992 req, struct nb_packet_read_state);
993 ssize_t nread;
994 int err;
996 nread = read_packet_recv(subreq, state, &state->buf, &err);
997 if (nread == -1) {
998 tevent_req_nterror(req, map_nt_error_from_unix(err));
999 return;
1001 state->buflen = nread;
1002 tevent_req_done(req);
1005 NTSTATUS nb_packet_read_recv(struct tevent_req *req,
1006 struct packet_struct **ppacket)
1008 struct nb_packet_read_state *state = tevent_req_data(
1009 req, struct nb_packet_read_state);
1010 struct nb_packet_client_header hdr;
1011 struct packet_struct *packet;
1012 NTSTATUS status;
1014 if (tevent_req_is_nterror(req, &status)) {
1015 return status;
1018 memcpy(&hdr, state->buf, sizeof(hdr));
1020 packet = parse_packet(
1021 (char *)state->buf + sizeof(struct nb_packet_client_header),
1022 state->buflen - sizeof(struct nb_packet_client_header),
1023 state->hdr.type, state->hdr.ip, state->hdr.port);
1024 if (packet == NULL) {
1025 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1027 *ppacket = packet;
1028 return NT_STATUS_OK;