libcli/named_pipe_auth: pass gssapi delegated credentials through the named pipe
[Samba/aatanasov.git] / libcli / named_pipe_auth / npa_tstream.c
blob1c9ab8f626b5f40339c680d3f4a80fa9608be5ec
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 *sam_info3,
70 DATA_BLOB session_key,
71 DATA_BLOB delegated_creds)
73 struct tevent_req *req;
74 struct tstream_npa_connect_state *state;
75 struct tevent_req *subreq;
76 int ret;
77 enum ndr_err_code ndr_err;
79 req = tevent_req_create(mem_ctx, &state,
80 struct tstream_npa_connect_state);
81 if (!req) {
82 return NULL;
85 state->caller.ev = ev;
86 state->caller.smb_iconv_c = smb_iconv_c;
88 state->unix_path = talloc_asprintf(state, "%s/%s",
89 directory,
90 npipe);
91 if (tevent_req_nomem(state->unix_path, req)) {
92 goto post;
95 ret = tsocket_address_unix_from_path(state,
96 "",
97 &state->unix_laddr);
98 if (ret == -1) {
99 tevent_req_error(req, errno);
100 goto post;
103 ret = tsocket_address_unix_from_path(state,
104 state->unix_path,
105 &state->unix_raddr);
106 if (ret == -1) {
107 tevent_req_error(req, errno);
108 goto post;
111 ZERO_STRUCT(state->auth_req);
112 if (client) {
113 struct named_pipe_auth_req_info3 *info3;
115 if (!server) {
116 tevent_req_error(req, EINVAL);
117 goto post;
120 state->auth_req.level = 3;
121 info3 = &state->auth_req.info.info3;
123 info3->client_name = client_name_in;
124 info3->client_addr = tsocket_address_inet_addr_string(client, state);
125 if (!info3->client_addr) {
126 /* errno might be EINVAL */
127 tevent_req_error(req, errno);
128 goto post;
130 info3->client_port = tsocket_address_inet_port(client);
131 if (!info3->client_name) {
132 info3->client_name = info3->client_addr;
135 info3->server_addr = tsocket_address_inet_addr_string(server, state);
136 if (!info3->server_addr) {
137 /* errno might be EINVAL */
138 tevent_req_error(req, errno);
139 goto post;
141 info3->server_port = tsocket_address_inet_port(server);
142 if (!info3->server_name) {
143 info3->server_name = info3->server_addr;
146 info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3);
147 info3->session_key_length = session_key.length;
148 info3->session_key = session_key.data;
149 info3->gssapi_delegated_creds_length = delegated_creds.length;
150 info3->gssapi_delegated_creds = delegated_creds.data;
152 } else if (sam_info3) {
153 state->auth_req.level = 1;
154 state->auth_req.info.info1 = *sam_info3;
155 } else {
156 state->auth_req.level = 0;
159 if (DEBUGLVL(10)) {
160 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
163 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
164 state, smb_iconv_c, &state->auth_req,
165 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
166 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
167 tevent_req_error(req, EINVAL);
168 goto post;
171 state->auth_req_iov.iov_base = state->auth_req_blob.data;
172 state->auth_req_iov.iov_len = state->auth_req_blob.length;
174 subreq = tstream_unix_connect_send(state,
175 state->caller.ev,
176 state->unix_laddr,
177 state->unix_raddr);
178 if (tevent_req_nomem(subreq, req)) {
179 goto post;
181 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
183 return req;
185 post:
186 tevent_req_post(req, ev);
187 return req;
190 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
192 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
194 struct tevent_req *req =
195 tevent_req_callback_data(subreq,
196 struct tevent_req);
197 struct tstream_npa_connect_state *state =
198 tevent_req_data(req,
199 struct tstream_npa_connect_state);
200 int ret;
201 int sys_errno;
203 ret = tstream_unix_connect_recv(subreq, &sys_errno,
204 state, &state->unix_stream);
205 TALLOC_FREE(subreq);
206 if (ret == -1) {
207 tevent_req_error(req, sys_errno);
208 return;
211 subreq = tstream_writev_send(state,
212 state->caller.ev,
213 state->unix_stream,
214 &state->auth_req_iov, 1);
215 if (tevent_req_nomem(subreq, req)) {
216 return;
218 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
221 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
222 void *private_data,
223 TALLOC_CTX *mem_ctx,
224 struct iovec **_vector,
225 size_t *_count);
226 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
228 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
230 struct tevent_req *req =
231 tevent_req_callback_data(subreq,
232 struct tevent_req);
233 struct tstream_npa_connect_state *state =
234 tevent_req_data(req,
235 struct tstream_npa_connect_state);
236 int ret;
237 int sys_errno;
239 ret = tstream_writev_recv(subreq, &sys_errno);
240 TALLOC_FREE(subreq);
241 if (ret == -1) {
242 tevent_req_error(req, sys_errno);
243 return;
246 state->auth_rep_blob = data_blob_const(NULL, 0);
248 subreq = tstream_readv_pdu_send(state, state->caller.ev,
249 state->unix_stream,
250 tstream_npa_connect_next_vector,
251 state);
252 if (tevent_req_nomem(subreq, req)) {
253 return;
255 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
258 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
259 void *private_data,
260 TALLOC_CTX *mem_ctx,
261 struct iovec **_vector,
262 size_t *_count)
264 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
265 struct tstream_npa_connect_state);
266 struct iovec *vector;
267 size_t count;
268 off_t ofs = 0;
270 if (state->auth_rep_blob.length == 0) {
271 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
272 if (!state->auth_rep_blob.data) {
273 return -1;
275 } else if (state->auth_rep_blob.length == 4) {
276 uint32_t msg_len;
278 ofs = 4;
280 msg_len = RIVAL(state->auth_rep_blob.data, 0);
282 if (msg_len > 0x00FFFFFF) {
283 errno = EMSGSIZE;
284 return -1;
287 if (msg_len == 0) {
288 errno = EMSGSIZE;
289 return -1;
292 msg_len += ofs;
294 state->auth_rep_blob.data = talloc_realloc(state,
295 state->auth_rep_blob.data,
296 uint8_t, msg_len);
297 if (!state->auth_rep_blob.data) {
298 return -1;
300 state->auth_rep_blob.length = msg_len;
301 } else {
302 *_vector = NULL;
303 *_count = 0;
304 return 0;
307 /* we need to get a message header */
308 vector = talloc_array(mem_ctx, struct iovec, 1);
309 if (!vector) {
310 return -1;
312 vector[0].iov_base = state->auth_rep_blob.data + ofs;
313 vector[0].iov_len = state->auth_rep_blob.length - ofs;
314 count = 1;
316 *_vector = vector;
317 *_count = count;
318 return 0;
321 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
323 struct tevent_req *req =
324 tevent_req_callback_data(subreq,
325 struct tevent_req);
326 struct tstream_npa_connect_state *state =
327 tevent_req_data(req,
328 struct tstream_npa_connect_state);
329 int ret;
330 int sys_errno;
331 enum ndr_err_code ndr_err;
333 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
334 TALLOC_FREE(subreq);
335 if (ret == -1) {
336 tevent_req_error(req, sys_errno);
337 return;
340 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
341 (uint32_t)state->auth_rep_blob.length));
342 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
344 ndr_err = ndr_pull_struct_blob(
345 &state->auth_rep_blob, state,
346 state->caller.smb_iconv_c, &state->auth_rep,
347 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
349 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
350 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
351 ndr_map_error2string(ndr_err)));
352 tevent_req_error(req, EIO);
353 return;
356 if (DEBUGLVL(10)) {
357 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
360 if (state->auth_rep.length < 16) {
361 DEBUG(0, ("req invalid length: %u < 16\n",
362 state->auth_rep.length));
363 tevent_req_error(req, EIO);
364 return;
367 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
368 DEBUG(0, ("req invalid magic: %s != %s\n",
369 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
370 tevent_req_error(req, EIO);
371 return;
374 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
375 DEBUG(0, ("req failed: %s\n",
376 nt_errstr(state->auth_rep.status)));
377 tevent_req_error(req, EACCES);
378 return;
381 if (state->auth_rep.level != state->auth_req.level) {
382 DEBUG(0, ("req invalid level: %u != %u\n",
383 state->auth_rep.level, state->auth_req.level));
384 tevent_req_error(req, EIO);
385 return;
388 tevent_req_done(req);
391 int _tstream_npa_connect_recv(struct tevent_req *req,
392 int *perrno,
393 TALLOC_CTX *mem_ctx,
394 struct tstream_context **_stream,
395 uint16_t *_file_type,
396 uint16_t *_device_state,
397 uint64_t *_allocation_size,
398 const char *location)
400 struct tstream_npa_connect_state *state =
401 tevent_req_data(req,
402 struct tstream_npa_connect_state);
403 struct tstream_context *stream;
404 struct tstream_npa *npas;
405 uint16_t device_state = 0;
406 uint64_t allocation_size = 0;
408 if (tevent_req_is_unix_error(req, perrno)) {
409 tevent_req_received(req);
410 return -1;
413 stream = tstream_context_create(mem_ctx,
414 &tstream_npa_ops,
415 &npas,
416 struct tstream_npa,
417 location);
418 if (!stream) {
419 return -1;
421 ZERO_STRUCTP(npas);
423 npas->unix_stream = talloc_move(stream, &state->unix_stream);
424 switch (state->auth_rep.level) {
425 case 0:
426 case 1:
427 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
428 device_state = 0x00ff;
429 allocation_size = 2048;
430 break;
431 case 2:
432 npas->file_type = state->auth_rep.info.info2.file_type;
433 device_state = state->auth_rep.info.info2.device_state;
434 allocation_size = state->auth_rep.info.info2.allocation_size;
435 break;
436 case 3:
437 npas->file_type = state->auth_rep.info.info3.file_type;
438 device_state = state->auth_rep.info.info3.device_state;
439 allocation_size = state->auth_rep.info.info3.allocation_size;
440 break;
443 *_stream = stream;
444 *_file_type = npas->file_type;
445 *_device_state = device_state;
446 *_allocation_size = allocation_size;
447 tevent_req_received(req);
448 return 0;
451 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
453 struct tstream_npa *npas = tstream_context_data(stream,
454 struct tstream_npa);
455 ssize_t ret;
457 if (!npas->unix_stream) {
458 errno = ENOTCONN;
459 return -1;
462 switch (npas->file_type) {
463 case FILE_TYPE_BYTE_MODE_PIPE:
464 ret = tstream_pending_bytes(npas->unix_stream);
465 break;
467 case FILE_TYPE_MESSAGE_MODE_PIPE:
468 ret = npas->pending.iov_len;
469 break;
471 default:
472 ret = -1;
475 return ret;
478 struct tstream_npa_readv_state {
479 struct tstream_context *stream;
481 struct iovec *vector;
482 size_t count;
484 /* the header for message mode */
485 uint8_t hdr[2];
486 bool wait_for_hdr;
488 int ret;
491 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
492 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
493 void *private_data,
494 TALLOC_CTX *mem_ctx,
495 struct iovec **_vector,
496 size_t *_count);
497 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
499 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
500 struct tevent_context *ev,
501 struct tstream_context *stream,
502 struct iovec *vector,
503 size_t count)
505 struct tevent_req *req;
506 struct tstream_npa_readv_state *state;
507 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
508 struct tevent_req *subreq;
509 off_t ofs;
510 size_t left;
511 uint8_t *pbase;
513 req = tevent_req_create(mem_ctx, &state,
514 struct tstream_npa_readv_state);
515 if (!req) {
516 return NULL;
519 state->stream = stream;
520 state->ret = 0;
522 if (!npas->unix_stream) {
523 tevent_req_error(req, ENOTCONN);
524 goto post;
527 switch (npas->file_type) {
528 case FILE_TYPE_BYTE_MODE_PIPE:
529 state->vector = vector;
530 state->count = count;
532 subreq = tstream_readv_send(state,
534 npas->unix_stream,
535 state->vector,
536 state->count);
537 if (tevent_req_nomem(subreq,req)) {
538 goto post;
540 tevent_req_set_callback(subreq,
541 tstream_npa_readv_byte_mode_handler,
542 req);
544 return req;
546 case FILE_TYPE_MESSAGE_MODE_PIPE:
548 * we make a copy of the vector and prepend a header
549 * with the length
551 state->vector = talloc_array(state, struct iovec, count);
552 if (tevent_req_nomem(state->vector, req)) {
553 goto post;
555 memcpy(state->vector, vector, sizeof(struct iovec)*count);
556 state->count = count;
559 * copy the pending buffer first
561 ofs = 0;
562 left = npas->pending.iov_len;
563 pbase = (uint8_t *)npas->pending.iov_base;
565 while (left > 0 && state->count > 0) {
566 uint8_t *base;
567 base = (uint8_t *)state->vector[0].iov_base;
568 if (left < state->vector[0].iov_len) {
569 memcpy(base, pbase + ofs, left);
571 base += left;
572 state->vector[0].iov_base = base;
573 state->vector[0].iov_len -= left;
575 ofs += left;
576 left = 0;
577 TALLOC_FREE(pbase);
578 ZERO_STRUCT(npas->pending);
579 break;
581 memcpy(base, pbase + ofs, state->vector[0].iov_len);
583 ofs += state->vector[0].iov_len;
584 left -= state->vector[0].iov_len;
585 state->vector += 1;
586 state->count -= 1;
588 if (left == 0) {
589 TALLOC_FREE(pbase);
590 ZERO_STRUCT(npas->pending);
591 break;
595 if (left > 0) {
596 memmove(pbase, pbase + ofs, left);
597 npas->pending.iov_base = pbase;
598 npas->pending.iov_len = left;
600 * this cannot fail and even if it
601 * fails we can handle it
603 pbase = talloc_realloc(npas, pbase, uint8_t, left);
604 if (pbase) {
605 npas->pending.iov_base = pbase;
607 pbase = NULL;
610 state->ret += ofs;
612 if (state->count == 0) {
613 tevent_req_done(req);
614 goto post;
617 ZERO_STRUCT(state->hdr);
618 state->wait_for_hdr = false;
620 subreq = tstream_readv_pdu_send(state,
622 npas->unix_stream,
623 tstream_npa_readv_next_vector,
624 state);
625 if (tevent_req_nomem(subreq, req)) {
626 goto post;
628 tevent_req_set_callback(subreq,
629 tstream_npa_readv_msg_mode_handler,
630 req);
632 return req;
635 /* this can't happen */
636 tevent_req_error(req, EINVAL);
637 goto post;
639 post:
640 tevent_req_post(req, ev);
641 return req;
644 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
646 struct tevent_req *req = tevent_req_callback_data(subreq,
647 struct tevent_req);
648 struct tstream_npa_readv_state *state = tevent_req_data(req,
649 struct tstream_npa_readv_state);
650 int ret;
651 int sys_errno;
653 ret = tstream_readv_recv(subreq, &sys_errno);
654 TALLOC_FREE(subreq);
655 if (ret == -1) {
656 tevent_req_error(req, sys_errno);
657 return;
660 state->ret = ret;
662 tevent_req_done(req);
665 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
666 void *private_data,
667 TALLOC_CTX *mem_ctx,
668 struct iovec **_vector,
669 size_t *_count)
671 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
672 struct tstream_npa_readv_state);
673 struct tstream_npa *npas = tstream_context_data(state->stream,
674 struct tstream_npa);
675 struct iovec *vector;
676 size_t count;
677 uint16_t msg_len;
678 size_t left;
680 if (state->count == 0) {
681 *_vector = NULL;
682 *_count = 0;
683 return 0;
686 if (!state->wait_for_hdr) {
687 /* we need to get a message header */
688 vector = talloc_array(mem_ctx, struct iovec, 1);
689 if (!vector) {
690 return -1;
692 ZERO_STRUCT(state->hdr);
693 vector[0].iov_base = state->hdr;
694 vector[0].iov_len = sizeof(state->hdr);
696 count = 1;
698 state->wait_for_hdr = true;
700 *_vector = vector;
701 *_count = count;
702 return 0;
705 /* and now fill the callers buffers and maybe the pending buffer */
706 state->wait_for_hdr = false;
708 msg_len = SVAL(state->hdr, 0);
710 if (msg_len == 0) {
711 errno = EIO;
712 return -1;
715 state->wait_for_hdr = false;
717 /* +1 because we may need to fill the pending buffer */
718 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
719 if (!vector) {
720 return -1;
723 count = 0;
724 left = msg_len;
725 while (left > 0 && state->count > 0) {
726 if (left < state->vector[0].iov_len) {
727 uint8_t *base;
728 base = (uint8_t *)state->vector[0].iov_base;
729 vector[count].iov_base = base;
730 vector[count].iov_len = left;
731 count++;
732 base += left;
733 state->vector[0].iov_base = base;
734 state->vector[0].iov_len -= left;
735 break;
737 vector[count] = state->vector[0];
738 count++;
739 left -= state->vector[0].iov_len;
740 state->vector += 1;
741 state->count -= 1;
744 if (left > 0) {
746 * if the message if longer than the buffers the caller
747 * requested, we need to consume the rest of the message
748 * into the pending buffer, where the next readv can
749 * be served from.
751 npas->pending.iov_base = talloc_array(npas, uint8_t, left);
752 if (!npas->pending.iov_base) {
753 return -1;
755 npas->pending.iov_len = left;
757 vector[count] = npas->pending;
758 count++;
761 state->ret += (msg_len - left);
763 *_vector = vector;
764 *_count = count;
765 return 0;
768 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
770 struct tevent_req *req = tevent_req_callback_data(subreq,
771 struct tevent_req);
772 int ret;
773 int sys_errno;
775 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
776 TALLOC_FREE(subreq);
777 if (ret == -1) {
778 tevent_req_error(req, sys_errno);
779 return;
783 * we do not set state->ret here as ret includes the headr size.
784 * we set it in tstream_npa_readv_pdu_next_vector()
787 tevent_req_done(req);
790 static int tstream_npa_readv_recv(struct tevent_req *req,
791 int *perrno)
793 struct tstream_npa_readv_state *state = tevent_req_data(req,
794 struct tstream_npa_readv_state);
795 int ret;
797 ret = tsocket_simple_int_recv(req, perrno);
798 if (ret == 0) {
799 ret = state->ret;
802 tevent_req_received(req);
803 return ret;
806 struct tstream_npa_writev_state {
807 const struct iovec *vector;
808 size_t count;
810 /* the header for message mode */
811 uint8_t hdr[2];
813 int ret;
816 static void tstream_npa_writev_handler(struct tevent_req *subreq);
818 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
819 struct tevent_context *ev,
820 struct tstream_context *stream,
821 const struct iovec *vector,
822 size_t count)
824 struct tevent_req *req;
825 struct tstream_npa_writev_state *state;
826 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
827 struct tevent_req *subreq;
828 size_t msg_len;
829 size_t i;
830 struct iovec *new_vector;
832 req = tevent_req_create(mem_ctx, &state,
833 struct tstream_npa_writev_state);
834 if (!req) {
835 return NULL;
838 state->ret = 0;
840 if (!npas->unix_stream) {
841 tevent_req_error(req, ENOTCONN);
842 goto post;
845 switch (npas->file_type) {
846 case FILE_TYPE_BYTE_MODE_PIPE:
847 state->vector = vector;
848 state->count = count;
849 break;
851 case FILE_TYPE_MESSAGE_MODE_PIPE:
853 * we make a copy of the vector and prepend a header
854 * with the length
856 new_vector = talloc_array(state, struct iovec, count + 1);
857 if (tevent_req_nomem(new_vector, req)) {
858 goto post;
860 new_vector[0].iov_base = state->hdr;
861 new_vector[0].iov_len = sizeof(state->hdr);
862 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
864 state->vector = new_vector;
865 state->count = count + 1;
867 msg_len = 0;
868 for (i=0; i < count; i++) {
869 msg_len += vector[i].iov_len;
872 if (msg_len > UINT16_MAX) {
873 tevent_req_error(req, EMSGSIZE);
874 goto post;
877 SSVAL(state->hdr, 0, msg_len);
878 break;
881 subreq = tstream_writev_send(state,
883 npas->unix_stream,
884 state->vector,
885 state->count);
886 if (tevent_req_nomem(subreq, req)) {
887 goto post;
889 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
891 return req;
893 post:
894 tevent_req_post(req, ev);
895 return req;
898 static void tstream_npa_writev_handler(struct tevent_req *subreq)
900 struct tevent_req *req = tevent_req_callback_data(subreq,
901 struct tevent_req);
902 struct tstream_npa_writev_state *state = tevent_req_data(req,
903 struct tstream_npa_writev_state);
904 int ret;
905 int sys_errno;
907 ret = tstream_writev_recv(subreq, &sys_errno);
908 TALLOC_FREE(subreq);
909 if (ret == -1) {
910 tevent_req_error(req, sys_errno);
911 return;
914 state->ret = ret;
916 tevent_req_done(req);
919 static int tstream_npa_writev_recv(struct tevent_req *req,
920 int *perrno)
922 struct tstream_npa_writev_state *state = tevent_req_data(req,
923 struct tstream_npa_writev_state);
924 int ret;
926 ret = tsocket_simple_int_recv(req, perrno);
927 if (ret == 0) {
928 ret = state->ret;
931 tevent_req_received(req);
932 return ret;
935 struct tstream_npa_disconnect_state {
936 struct tstream_context *stream;
939 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
941 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
942 struct tevent_context *ev,
943 struct tstream_context *stream)
945 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
946 struct tevent_req *req;
947 struct tstream_npa_disconnect_state *state;
948 struct tevent_req *subreq;
950 req = tevent_req_create(mem_ctx, &state,
951 struct tstream_npa_disconnect_state);
952 if (req == NULL) {
953 return NULL;
956 state->stream = stream;
958 if (!npas->unix_stream) {
959 tevent_req_error(req, ENOTCONN);
960 goto post;
963 subreq = tstream_disconnect_send(state,
965 npas->unix_stream);
966 if (tevent_req_nomem(subreq, req)) {
967 goto post;
969 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
971 return req;
973 post:
974 tevent_req_post(req, ev);
975 return req;
978 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
980 struct tevent_req *req = tevent_req_callback_data(subreq,
981 struct tevent_req);
982 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
983 struct tstream_npa_disconnect_state);
984 struct tstream_context *stream = state->stream;
985 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
986 int ret;
987 int sys_errno;
989 ret = tstream_disconnect_recv(subreq, &sys_errno);
990 TALLOC_FREE(subreq);
991 if (ret == -1) {
992 tevent_req_error(req, sys_errno);
993 return;
996 TALLOC_FREE(npas->unix_stream);
998 tevent_req_done(req);
1001 static int tstream_npa_disconnect_recv(struct tevent_req *req,
1002 int *perrno)
1004 int ret;
1006 ret = tsocket_simple_int_recv(req, perrno);
1008 tevent_req_received(req);
1009 return ret;
1012 static const struct tstream_context_ops tstream_npa_ops = {
1013 .name = "npa",
1015 .pending_bytes = tstream_npa_pending_bytes,
1017 .readv_send = tstream_npa_readv_send,
1018 .readv_recv = tstream_npa_readv_recv,
1020 .writev_send = tstream_npa_writev_send,
1021 .writev_recv = tstream_npa_writev_recv,
1023 .disconnect_send = tstream_npa_disconnect_send,
1024 .disconnect_recv = tstream_npa_disconnect_recv,
1027 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1028 int fd,
1029 uint16_t file_type,
1030 struct tstream_context **_stream,
1031 const char *location)
1033 struct tstream_context *stream;
1034 struct tstream_npa *npas;
1035 int ret;
1037 switch (file_type) {
1038 case FILE_TYPE_BYTE_MODE_PIPE:
1039 break;
1040 case FILE_TYPE_MESSAGE_MODE_PIPE:
1041 break;
1042 default:
1043 errno = EINVAL;
1044 return -1;
1047 stream = tstream_context_create(mem_ctx,
1048 &tstream_npa_ops,
1049 &npas,
1050 struct tstream_npa,
1051 location);
1052 if (!stream) {
1053 return -1;
1055 ZERO_STRUCTP(npas);
1057 npas->file_type = file_type;
1059 ret = tstream_bsd_existing_socket(stream, fd,
1060 &npas->unix_stream);
1061 if (ret == -1) {
1062 int saved_errno = errno;
1063 talloc_free(stream);
1064 errno = saved_errno;
1065 return -1;
1068 *_stream = stream;
1069 return 0;