s3-netapi: implement NetShutdownInit_r and NetShutdownAbort_r.
[Samba.git] / libcli / named_pipe_auth / npa_tstream.c
blobfdb55c7e826dedd08ed00d341eb6522fc05b248a
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2009
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/>.
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../util/tevent_unix.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
26 #include "../libcli/named_pipe_auth/npa_tstream.h"
27 #include "libcli/raw/smb.h"
29 static const struct tstream_context_ops tstream_npa_ops;
31 struct tstream_npa {
32 struct tstream_context *unix_stream;
34 uint16_t file_type;
36 struct iovec pending;
39 struct tstream_npa_connect_state {
40 struct {
41 struct tevent_context *ev;
42 struct smb_iconv_convenience *smb_iconv_c;
43 } caller;
45 const char *unix_path;
46 struct tsocket_address *unix_laddr;
47 struct tsocket_address *unix_raddr;
48 struct tstream_context *unix_stream;
50 struct named_pipe_auth_req auth_req;
51 DATA_BLOB auth_req_blob;
52 struct iovec auth_req_iov;
54 struct named_pipe_auth_rep auth_rep;
55 DATA_BLOB auth_rep_blob;
58 static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
60 struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
61 struct tevent_context *ev,
62 struct smb_iconv_convenience *smb_iconv_c,
63 const char *directory,
64 const char *npipe,
65 const struct tsocket_address *client,
66 const char *client_name_in,
67 const struct tsocket_address *server,
68 const char *server_name,
69 const struct netr_SamInfo3 *info3,
70 DATA_BLOB session_key)
72 struct tevent_req *req;
73 struct tstream_npa_connect_state *state;
74 struct tevent_req *subreq;
75 int ret;
76 enum ndr_err_code ndr_err;
78 req = tevent_req_create(mem_ctx, &state,
79 struct tstream_npa_connect_state);
80 if (!req) {
81 return NULL;
84 state->caller.ev = ev;
85 state->caller.smb_iconv_c = smb_iconv_c;
87 state->unix_path = talloc_asprintf(state, "%s/%s",
88 directory,
89 npipe);
90 if (tevent_req_nomem(state->unix_path, req)) {
91 goto post;
94 ret = tsocket_address_unix_from_path(state,
95 "",
96 &state->unix_laddr);
97 if (ret == -1) {
98 tevent_req_error(req, errno);
99 goto post;
102 ret = tsocket_address_unix_from_path(state,
103 state->unix_path,
104 &state->unix_raddr);
105 if (ret == -1) {
106 tevent_req_error(req, errno);
107 goto post;
110 ZERO_STRUCT(state->auth_req);
111 if (client) {
112 struct named_pipe_auth_req_info2 *info2;
114 if (!server) {
115 tevent_req_error(req, EINVAL);
116 goto post;
119 state->auth_req.level = 2;
120 info2 = &state->auth_req.info.info2;
122 info2->client_name = client_name_in;
123 info2->client_addr = tsocket_address_inet_addr_string(client, state);
124 if (!info2->client_addr) {
125 /* errno might be EINVAL */
126 tevent_req_error(req, errno);
127 goto post;
129 info2->client_port = tsocket_address_inet_port(client);
130 if (!info2->client_name) {
131 info2->client_name = info2->client_addr;
134 info2->server_addr = tsocket_address_inet_addr_string(server, state);
135 if (!info2->server_addr) {
136 /* errno might be EINVAL */
137 tevent_req_error(req, errno);
138 goto post;
140 info2->server_port = tsocket_address_inet_port(server);
141 if (!info2->server_name) {
142 info2->server_name = info2->server_addr;
145 info2->sam_info3 = discard_const_p(struct netr_SamInfo3, info3);
146 info2->session_key_length = session_key.length;
147 info2->session_key = session_key.data;
148 } else if (info3) {
149 state->auth_req.level = 1;
150 state->auth_req.info.info1 = *info3;
151 } else {
152 state->auth_req.level = 0;
155 if (DEBUGLVL(10)) {
156 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
159 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
160 state, smb_iconv_c, &state->auth_req,
161 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
162 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
163 tevent_req_error(req, EINVAL);
164 goto post;
167 state->auth_req_iov.iov_base = state->auth_req_blob.data;
168 state->auth_req_iov.iov_len = state->auth_req_blob.length;
170 subreq = tstream_unix_connect_send(state,
171 state->caller.ev,
172 state->unix_laddr,
173 state->unix_raddr);
174 if (tevent_req_nomem(subreq, req)) {
175 goto post;
177 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
179 return req;
181 post:
182 tevent_req_post(req, ev);
183 return req;
186 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
188 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
190 struct tevent_req *req =
191 tevent_req_callback_data(subreq,
192 struct tevent_req);
193 struct tstream_npa_connect_state *state =
194 tevent_req_data(req,
195 struct tstream_npa_connect_state);
196 int ret;
197 int sys_errno;
199 ret = tstream_unix_connect_recv(subreq, &sys_errno,
200 state, &state->unix_stream);
201 TALLOC_FREE(subreq);
202 if (ret == -1) {
203 tevent_req_error(req, sys_errno);
204 return;
207 subreq = tstream_writev_send(state,
208 state->caller.ev,
209 state->unix_stream,
210 &state->auth_req_iov, 1);
211 if (tevent_req_nomem(subreq, req)) {
212 return;
214 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
217 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
218 void *private_data,
219 TALLOC_CTX *mem_ctx,
220 struct iovec **_vector,
221 size_t *_count);
222 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
224 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
226 struct tevent_req *req =
227 tevent_req_callback_data(subreq,
228 struct tevent_req);
229 struct tstream_npa_connect_state *state =
230 tevent_req_data(req,
231 struct tstream_npa_connect_state);
232 int ret;
233 int sys_errno;
235 ret = tstream_writev_recv(subreq, &sys_errno);
236 TALLOC_FREE(subreq);
237 if (ret == -1) {
238 tevent_req_error(req, sys_errno);
239 return;
242 state->auth_rep_blob = data_blob_const(NULL, 0);
244 subreq = tstream_readv_pdu_send(state, state->caller.ev,
245 state->unix_stream,
246 tstream_npa_connect_next_vector,
247 state);
248 if (tevent_req_nomem(subreq, req)) {
249 return;
251 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
254 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
255 void *private_data,
256 TALLOC_CTX *mem_ctx,
257 struct iovec **_vector,
258 size_t *_count)
260 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
261 struct tstream_npa_connect_state);
262 struct iovec *vector;
263 size_t count;
264 off_t ofs = 0;
266 if (state->auth_rep_blob.length == 0) {
267 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
268 if (!state->auth_rep_blob.data) {
269 return -1;
271 } else if (state->auth_rep_blob.length == 4) {
272 uint32_t msg_len;
274 ofs = 4;
276 msg_len = RIVAL(state->auth_rep_blob.data, 0);
278 if (msg_len > 0x00FFFFFF) {
279 errno = EMSGSIZE;
280 return -1;
283 if (msg_len == 0) {
284 errno = EMSGSIZE;
285 return -1;
288 msg_len += ofs;
290 state->auth_rep_blob.data = talloc_realloc(state,
291 state->auth_rep_blob.data,
292 uint8_t, msg_len);
293 if (!state->auth_rep_blob.data) {
294 return -1;
296 state->auth_rep_blob.length = msg_len;
297 } else {
298 *_vector = NULL;
299 *_count = 0;
300 return 0;
303 /* we need to get a message header */
304 vector = talloc_array(mem_ctx, struct iovec, 1);
305 if (!vector) {
306 return -1;
308 vector[0].iov_base = state->auth_rep_blob.data + ofs;
309 vector[0].iov_len = state->auth_rep_blob.length - ofs;
310 count = 1;
312 *_vector = vector;
313 *_count = count;
314 return 0;
317 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
319 struct tevent_req *req =
320 tevent_req_callback_data(subreq,
321 struct tevent_req);
322 struct tstream_npa_connect_state *state =
323 tevent_req_data(req,
324 struct tstream_npa_connect_state);
325 int ret;
326 int sys_errno;
327 enum ndr_err_code ndr_err;
329 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
330 TALLOC_FREE(subreq);
331 if (ret == -1) {
332 tevent_req_error(req, sys_errno);
333 return;
336 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
337 (uint32_t)state->auth_rep_blob.length));
338 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
340 ndr_err = ndr_pull_struct_blob(
341 &state->auth_rep_blob, state,
342 state->caller.smb_iconv_c, &state->auth_rep,
343 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
345 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
346 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
347 ndr_map_error2string(ndr_err)));
348 tevent_req_error(req, EIO);
349 return;
352 if (DEBUGLVL(10)) {
353 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
356 if (state->auth_rep.length < 16) {
357 DEBUG(0, ("req invalid length: %u < 16\n",
358 state->auth_rep.length));
359 tevent_req_error(req, EIO);
360 return;
363 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
364 DEBUG(0, ("req invalid magic: %s != %s\n",
365 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
366 tevent_req_error(req, EIO);
367 return;
370 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
371 DEBUG(0, ("req failed: %s\n",
372 nt_errstr(state->auth_rep.status)));
373 tevent_req_error(req, EACCES);
374 return;
377 if (state->auth_rep.level != state->auth_req.level) {
378 DEBUG(0, ("req invalid level: %u != %u\n",
379 state->auth_rep.level, state->auth_req.level));
380 tevent_req_error(req, EIO);
381 return;
384 tevent_req_done(req);
387 int _tstream_npa_connect_recv(struct tevent_req *req,
388 int *perrno,
389 TALLOC_CTX *mem_ctx,
390 struct tstream_context **_stream,
391 uint16_t *_file_type,
392 uint16_t *_device_state,
393 uint64_t *_allocation_size,
394 const char *location)
396 struct tstream_npa_connect_state *state =
397 tevent_req_data(req,
398 struct tstream_npa_connect_state);
399 struct tstream_context *stream;
400 struct tstream_npa *npas;
401 uint16_t device_state = 0;
402 uint64_t allocation_size = 0;
404 if (tevent_req_is_unix_error(req, perrno)) {
405 tevent_req_received(req);
406 return -1;
409 stream = tstream_context_create(mem_ctx,
410 &tstream_npa_ops,
411 &npas,
412 struct tstream_npa,
413 location);
414 if (!stream) {
415 return -1;
417 ZERO_STRUCTP(npas);
419 npas->unix_stream = talloc_move(stream, &state->unix_stream);
420 switch (state->auth_rep.level) {
421 case 0:
422 case 1:
423 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
424 device_state = 0x00ff;
425 allocation_size = 2048;
426 break;
427 case 2:
428 npas->file_type = state->auth_rep.info.info2.file_type;
429 device_state = state->auth_rep.info.info2.device_state;
430 allocation_size = state->auth_rep.info.info2.allocation_size;
431 break;
434 *_stream = stream;
435 *_file_type = npas->file_type;
436 *_device_state = device_state;
437 *_allocation_size = allocation_size;
438 tevent_req_received(req);
439 return 0;
442 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
444 struct tstream_npa *npas = tstream_context_data(stream,
445 struct tstream_npa);
446 ssize_t ret;
448 if (!npas->unix_stream) {
449 errno = ENOTCONN;
450 return -1;
453 switch (npas->file_type) {
454 case FILE_TYPE_BYTE_MODE_PIPE:
455 ret = tstream_pending_bytes(npas->unix_stream);
456 break;
458 case FILE_TYPE_MESSAGE_MODE_PIPE:
459 ret = npas->pending.iov_len;
460 break;
462 default:
463 ret = -1;
466 return ret;
469 struct tstream_npa_readv_state {
470 struct tstream_context *stream;
472 struct iovec *vector;
473 size_t count;
475 /* the header for message mode */
476 uint8_t hdr[2];
477 bool wait_for_hdr;
479 int ret;
482 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
483 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
484 void *private_data,
485 TALLOC_CTX *mem_ctx,
486 struct iovec **_vector,
487 size_t *_count);
488 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
490 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
491 struct tevent_context *ev,
492 struct tstream_context *stream,
493 struct iovec *vector,
494 size_t count)
496 struct tevent_req *req;
497 struct tstream_npa_readv_state *state;
498 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
499 struct tevent_req *subreq;
500 off_t ofs;
501 size_t left;
502 uint8_t *pbase;
504 req = tevent_req_create(mem_ctx, &state,
505 struct tstream_npa_readv_state);
506 if (!req) {
507 return NULL;
510 state->stream = stream;
511 state->ret = 0;
513 if (!npas->unix_stream) {
514 tevent_req_error(req, ENOTCONN);
515 goto post;
518 switch (npas->file_type) {
519 case FILE_TYPE_BYTE_MODE_PIPE:
520 state->vector = vector;
521 state->count = count;
523 subreq = tstream_readv_send(state,
525 npas->unix_stream,
526 state->vector,
527 state->count);
528 if (tevent_req_nomem(subreq,req)) {
529 goto post;
531 tevent_req_set_callback(subreq,
532 tstream_npa_readv_byte_mode_handler,
533 req);
535 return req;
537 case FILE_TYPE_MESSAGE_MODE_PIPE:
539 * we make a copy of the vector and prepend a header
540 * with the length
542 state->vector = talloc_array(state, struct iovec, count);
543 if (tevent_req_nomem(state->vector, req)) {
544 goto post;
546 memcpy(state->vector, vector, sizeof(struct iovec)*count);
547 state->count = count;
550 * copy the pending buffer first
552 ofs = 0;
553 left = npas->pending.iov_len;
554 pbase = (uint8_t *)npas->pending.iov_base;
556 while (left > 0 && state->count > 0) {
557 uint8_t *base;
558 base = (uint8_t *)state->vector[0].iov_base;
559 if (left < state->vector[0].iov_len) {
560 memcpy(base, pbase + ofs, left);
562 base += left;
563 state->vector[0].iov_base = base;
564 state->vector[0].iov_len -= left;
566 ofs += left;
567 left = 0;
568 TALLOC_FREE(pbase);
569 ZERO_STRUCT(npas->pending);
570 break;
572 memcpy(base, pbase + ofs, state->vector[0].iov_len);
574 ofs += state->vector[0].iov_len;
575 left -= state->vector[0].iov_len;
576 state->vector += 1;
577 state->count -= 1;
579 if (left == 0) {
580 TALLOC_FREE(pbase);
581 ZERO_STRUCT(npas->pending);
582 break;
586 if (left > 0) {
587 memmove(pbase, pbase + ofs, left);
588 npas->pending.iov_base = pbase;
589 npas->pending.iov_len = left;
591 * this cannot fail and even if it
592 * fails we can handle it
594 pbase = talloc_realloc(npas, pbase, uint8_t, left);
595 if (pbase) {
596 npas->pending.iov_base = pbase;
598 pbase = NULL;
601 state->ret += ofs;
603 if (state->count == 0) {
604 tevent_req_done(req);
605 goto post;
608 ZERO_STRUCT(state->hdr);
609 state->wait_for_hdr = false;
611 subreq = tstream_readv_pdu_send(state,
613 npas->unix_stream,
614 tstream_npa_readv_next_vector,
615 state);
616 if (tevent_req_nomem(subreq, req)) {
617 goto post;
619 tevent_req_set_callback(subreq,
620 tstream_npa_readv_msg_mode_handler,
621 req);
623 return req;
626 /* this can't happen */
627 tevent_req_error(req, EINVAL);
628 goto post;
630 post:
631 tevent_req_post(req, ev);
632 return req;
635 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
637 struct tevent_req *req = tevent_req_callback_data(subreq,
638 struct tevent_req);
639 struct tstream_npa_readv_state *state = tevent_req_data(req,
640 struct tstream_npa_readv_state);
641 int ret;
642 int sys_errno;
644 ret = tstream_readv_recv(subreq, &sys_errno);
645 TALLOC_FREE(subreq);
646 if (ret == -1) {
647 tevent_req_error(req, sys_errno);
648 return;
651 state->ret = ret;
653 tevent_req_done(req);
656 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
657 void *private_data,
658 TALLOC_CTX *mem_ctx,
659 struct iovec **_vector,
660 size_t *_count)
662 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
663 struct tstream_npa_readv_state);
664 struct tstream_npa *npas = tstream_context_data(state->stream,
665 struct tstream_npa);
666 struct iovec *vector;
667 size_t count;
668 uint16_t msg_len;
669 size_t left;
671 if (state->count == 0) {
672 *_vector = NULL;
673 *_count = 0;
674 return 0;
677 if (!state->wait_for_hdr) {
678 /* we need to get a message header */
679 vector = talloc_array(mem_ctx, struct iovec, 1);
680 if (!vector) {
681 return -1;
683 ZERO_STRUCT(state->hdr);
684 vector[0].iov_base = state->hdr;
685 vector[0].iov_len = sizeof(state->hdr);
687 count = 1;
689 state->wait_for_hdr = true;
691 *_vector = vector;
692 *_count = count;
693 return 0;
696 /* and now fill the callers buffers and maybe the pending buffer */
697 state->wait_for_hdr = false;
699 msg_len = SVAL(state->hdr, 0);
701 if (msg_len == 0) {
702 errno = EIO;
703 return -1;
706 state->wait_for_hdr = false;
708 /* +1 because we may need to fill the pending buffer */
709 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
710 if (!vector) {
711 return -1;
714 count = 0;
715 left = msg_len;
716 while (left > 0 && state->count > 0) {
717 if (left < state->vector[0].iov_len) {
718 uint8_t *base;
719 base = (uint8_t *)state->vector[0].iov_base;
720 vector[count].iov_base = base;
721 vector[count].iov_len = left;
722 count++;
723 base += left;
724 state->vector[0].iov_base = base;
725 state->vector[0].iov_len -= left;
726 break;
728 vector[count] = state->vector[0];
729 count++;
730 left -= state->vector[0].iov_len;
731 state->vector += 1;
732 state->count -= 1;
735 if (left > 0) {
737 * if the message if longer than the buffers the caller
738 * requested, we need to consume the rest of the message
739 * into the pending buffer, where the next readv can
740 * be served from.
742 npas->pending.iov_base = talloc_array(npas, uint8_t, left);
743 if (!npas->pending.iov_base) {
744 return -1;
746 npas->pending.iov_len = left;
748 vector[count] = npas->pending;
749 count++;
752 state->ret += (msg_len - left);
754 *_vector = vector;
755 *_count = count;
756 return 0;
759 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
761 struct tevent_req *req = tevent_req_callback_data(subreq,
762 struct tevent_req);
763 int ret;
764 int sys_errno;
766 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
767 TALLOC_FREE(subreq);
768 if (ret == -1) {
769 tevent_req_error(req, sys_errno);
770 return;
774 * we do not set state->ret here as ret includes the headr size.
775 * we set it in tstream_npa_readv_pdu_next_vector()
778 tevent_req_done(req);
781 static int tstream_npa_readv_recv(struct tevent_req *req,
782 int *perrno)
784 struct tstream_npa_readv_state *state = tevent_req_data(req,
785 struct tstream_npa_readv_state);
786 int ret;
788 ret = tsocket_simple_int_recv(req, perrno);
789 if (ret == 0) {
790 ret = state->ret;
793 tevent_req_received(req);
794 return ret;
797 struct tstream_npa_writev_state {
798 const struct iovec *vector;
799 size_t count;
801 /* the header for message mode */
802 uint8_t hdr[2];
804 int ret;
807 static void tstream_npa_writev_handler(struct tevent_req *subreq);
809 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
810 struct tevent_context *ev,
811 struct tstream_context *stream,
812 const struct iovec *vector,
813 size_t count)
815 struct tevent_req *req;
816 struct tstream_npa_writev_state *state;
817 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
818 struct tevent_req *subreq;
819 size_t msg_len;
820 size_t i;
821 struct iovec *new_vector;
823 req = tevent_req_create(mem_ctx, &state,
824 struct tstream_npa_writev_state);
825 if (!req) {
826 return NULL;
829 state->ret = 0;
831 if (!npas->unix_stream) {
832 tevent_req_error(req, ENOTCONN);
833 goto post;
836 switch (npas->file_type) {
837 case FILE_TYPE_BYTE_MODE_PIPE:
838 state->vector = vector;
839 state->count = count;
840 break;
842 case FILE_TYPE_MESSAGE_MODE_PIPE:
844 * we make a copy of the vector and prepend a header
845 * with the length
847 new_vector = talloc_array(state, struct iovec, count + 1);
848 if (tevent_req_nomem(new_vector, req)) {
849 goto post;
851 new_vector[0].iov_base = state->hdr;
852 new_vector[0].iov_len = sizeof(state->hdr);
853 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
855 state->vector = new_vector;
856 state->count = count + 1;
858 msg_len = 0;
859 for (i=0; i < count; i++) {
860 msg_len += vector[i].iov_len;
863 if (msg_len > UINT16_MAX) {
864 tevent_req_error(req, EMSGSIZE);
865 goto post;
868 SSVAL(state->hdr, 0, msg_len);
869 break;
872 subreq = tstream_writev_send(state,
874 npas->unix_stream,
875 state->vector,
876 state->count);
877 if (tevent_req_nomem(subreq, req)) {
878 goto post;
880 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
882 return req;
884 post:
885 tevent_req_post(req, ev);
886 return req;
889 static void tstream_npa_writev_handler(struct tevent_req *subreq)
891 struct tevent_req *req = tevent_req_callback_data(subreq,
892 struct tevent_req);
893 struct tstream_npa_writev_state *state = tevent_req_data(req,
894 struct tstream_npa_writev_state);
895 int ret;
896 int sys_errno;
898 ret = tstream_writev_recv(subreq, &sys_errno);
899 TALLOC_FREE(subreq);
900 if (ret == -1) {
901 tevent_req_error(req, sys_errno);
902 return;
905 state->ret = ret;
907 tevent_req_done(req);
910 static int tstream_npa_writev_recv(struct tevent_req *req,
911 int *perrno)
913 struct tstream_npa_writev_state *state = tevent_req_data(req,
914 struct tstream_npa_writev_state);
915 int ret;
917 ret = tsocket_simple_int_recv(req, perrno);
918 if (ret == 0) {
919 ret = state->ret;
922 tevent_req_received(req);
923 return ret;
926 struct tstream_npa_disconnect_state {
927 struct tstream_context *stream;
930 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
932 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
933 struct tevent_context *ev,
934 struct tstream_context *stream)
936 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
937 struct tevent_req *req;
938 struct tstream_npa_disconnect_state *state;
939 struct tevent_req *subreq;
941 req = tevent_req_create(mem_ctx, &state,
942 struct tstream_npa_disconnect_state);
943 if (req == NULL) {
944 return NULL;
947 state->stream = stream;
949 if (!npas->unix_stream) {
950 tevent_req_error(req, ENOTCONN);
951 goto post;
954 subreq = tstream_disconnect_send(state,
956 npas->unix_stream);
957 if (tevent_req_nomem(subreq, req)) {
958 goto post;
960 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
962 return req;
964 post:
965 tevent_req_post(req, ev);
966 return req;
969 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
971 struct tevent_req *req = tevent_req_callback_data(subreq,
972 struct tevent_req);
973 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
974 struct tstream_npa_disconnect_state);
975 struct tstream_context *stream = state->stream;
976 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
977 int ret;
978 int sys_errno;
980 ret = tstream_disconnect_recv(subreq, &sys_errno);
981 TALLOC_FREE(subreq);
982 if (ret == -1) {
983 tevent_req_error(req, sys_errno);
984 return;
987 TALLOC_FREE(npas->unix_stream);
989 tevent_req_done(req);
992 static int tstream_npa_disconnect_recv(struct tevent_req *req,
993 int *perrno)
995 int ret;
997 ret = tsocket_simple_int_recv(req, perrno);
999 tevent_req_received(req);
1000 return ret;
1003 static const struct tstream_context_ops tstream_npa_ops = {
1004 .name = "npa",
1006 .pending_bytes = tstream_npa_pending_bytes,
1008 .readv_send = tstream_npa_readv_send,
1009 .readv_recv = tstream_npa_readv_recv,
1011 .writev_send = tstream_npa_writev_send,
1012 .writev_recv = tstream_npa_writev_recv,
1014 .disconnect_send = tstream_npa_disconnect_send,
1015 .disconnect_recv = tstream_npa_disconnect_recv,
1018 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1019 int fd,
1020 uint16_t file_type,
1021 struct tstream_context **_stream,
1022 const char *location)
1024 struct tstream_context *stream;
1025 struct tstream_npa *npas;
1026 int ret;
1028 switch (file_type) {
1029 case FILE_TYPE_BYTE_MODE_PIPE:
1030 break;
1031 case FILE_TYPE_MESSAGE_MODE_PIPE:
1032 break;
1033 default:
1034 errno = EINVAL;
1035 return -1;
1038 stream = tstream_context_create(mem_ctx,
1039 &tstream_npa_ops,
1040 &npas,
1041 struct tstream_npa,
1042 location);
1043 if (!stream) {
1044 return -1;
1046 ZERO_STRUCTP(npas);
1048 npas->file_type = file_type;
1050 ret = tstream_bsd_existing_socket(stream, fd,
1051 &npas->unix_stream);
1052 if (ret == -1) {
1053 int saved_errno = errno;
1054 talloc_free(stream);
1055 errno = saved_errno;
1056 return -1;
1059 *_stream = stream;
1060 return 0;