s3: smbd: Fix schedule_smb2_aio_read() to allow the last read in a compound to go...
[Samba.git] / libcli / named_pipe_auth / npa_tstream.c
blob506c4a35681697d1e12c67be28bc8597a067b36e
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/named_pipe_auth/tstream_u32_read.h"
28 #include "../libcli/smb/smb_constants.h"
30 static const struct tstream_context_ops tstream_npa_ops;
32 struct tstream_npa {
33 struct tstream_context *unix_stream;
35 uint16_t file_type;
37 struct iovec pending;
40 struct tstream_npa_connect_state {
41 struct {
42 struct tevent_context *ev;
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;
57 static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
59 struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
60 struct tevent_context *ev,
61 const char *directory,
62 const char *npipe,
63 enum dcerpc_transport_t transport,
64 const struct tsocket_address *remote_client_addr,
65 const char *remote_client_name_in,
66 const struct tsocket_address *local_server_addr,
67 const char *local_server_name_in,
68 const struct auth_session_info_transport *session_info)
70 struct tevent_req *req;
71 struct tstream_npa_connect_state *state;
72 struct tevent_req *subreq;
73 int ret;
74 enum ndr_err_code ndr_err;
75 char *lower_case_npipe;
76 struct named_pipe_auth_req_info5 *info5;
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;
86 lower_case_npipe = strlower_talloc(state, npipe);
87 if (tevent_req_nomem(lower_case_npipe, req)) {
88 goto post;
91 state->unix_path = talloc_asprintf(state, "%s/%s",
92 directory,
93 lower_case_npipe);
94 talloc_free(lower_case_npipe);
95 if (tevent_req_nomem(state->unix_path, req)) {
96 goto post;
99 ret = tsocket_address_unix_from_path(state,
101 &state->unix_laddr);
102 if (ret == -1) {
103 tevent_req_error(req, errno);
104 goto post;
107 ret = tsocket_address_unix_from_path(state,
108 state->unix_path,
109 &state->unix_raddr);
110 if (ret == -1) {
111 tevent_req_error(req, errno);
112 goto post;
115 ZERO_STRUCT(state->auth_req);
117 if (!local_server_addr) {
118 tevent_req_error(req, EINVAL);
119 goto post;
122 state->auth_req.level = 5;
123 info5 = &state->auth_req.info.info5;
125 info5->transport = transport;
126 SMB_ASSERT(info5->transport == transport); /* Assert no overflow */
128 info5->remote_client_name = remote_client_name_in;
129 info5->remote_client_addr = tsocket_address_inet_addr_string(remote_client_addr,
130 state);
131 if (!info5->remote_client_addr) {
132 /* errno might be EINVAL */
133 tevent_req_error(req, errno);
134 goto post;
136 info5->remote_client_port = tsocket_address_inet_port(remote_client_addr);
137 if (!info5->remote_client_name) {
138 info5->remote_client_name = info5->remote_client_addr;
141 info5->local_server_name = local_server_name_in;
142 info5->local_server_addr = tsocket_address_inet_addr_string(local_server_addr,
143 state);
144 if (!info5->local_server_addr) {
145 /* errno might be EINVAL */
146 tevent_req_error(req, errno);
147 goto post;
149 info5->local_server_port = tsocket_address_inet_port(local_server_addr);
150 if (!info5->local_server_name) {
151 info5->local_server_name = info5->local_server_addr;
154 info5->session_info = discard_const_p(struct auth_session_info_transport, session_info);
156 if (DEBUGLVL(10)) {
157 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
160 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
161 state, &state->auth_req,
162 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
163 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
164 tevent_req_error(req, EINVAL);
165 goto post;
168 state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
169 state->auth_req_iov.iov_len = state->auth_req_blob.length;
171 subreq = tstream_unix_connect_send(state,
172 state->caller.ev,
173 state->unix_laddr,
174 state->unix_raddr);
175 if (tevent_req_nomem(subreq, req)) {
176 goto post;
178 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
180 return req;
182 post:
183 tevent_req_post(req, ev);
184 return req;
187 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
189 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
191 struct tevent_req *req =
192 tevent_req_callback_data(subreq,
193 struct tevent_req);
194 struct tstream_npa_connect_state *state =
195 tevent_req_data(req,
196 struct tstream_npa_connect_state);
197 int ret;
198 int sys_errno;
200 ret = tstream_unix_connect_recv(subreq, &sys_errno,
201 state, &state->unix_stream);
202 TALLOC_FREE(subreq);
203 if (ret == -1) {
204 tevent_req_error(req, sys_errno);
205 return;
208 subreq = tstream_writev_send(state,
209 state->caller.ev,
210 state->unix_stream,
211 &state->auth_req_iov, 1);
212 if (tevent_req_nomem(subreq, req)) {
213 return;
215 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
218 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
220 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
222 struct tevent_req *req =
223 tevent_req_callback_data(subreq,
224 struct tevent_req);
225 struct tstream_npa_connect_state *state =
226 tevent_req_data(req,
227 struct tstream_npa_connect_state);
228 int ret;
229 int sys_errno;
231 ret = tstream_writev_recv(subreq, &sys_errno);
232 TALLOC_FREE(subreq);
233 if (ret == -1) {
234 tevent_req_error(req, sys_errno);
235 return;
238 subreq = tstream_u32_read_send(
239 state, state->caller.ev, 0x00FFFFFF, state->unix_stream);
240 if (tevent_req_nomem(subreq, req)) {
241 return;
243 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
246 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
248 struct tevent_req *req =
249 tevent_req_callback_data(subreq,
250 struct tevent_req);
251 struct tstream_npa_connect_state *state =
252 tevent_req_data(req,
253 struct tstream_npa_connect_state);
254 DATA_BLOB in;
255 int err;
256 enum ndr_err_code ndr_err;
258 err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
259 TALLOC_FREE(subreq);
260 if (tevent_req_error(req, err)) {
261 return;
264 DBG_DEBUG("name_pipe_auth_rep(client)[%zu]\n", in.length);
265 dump_data(11, in.data, in.length);
267 ndr_err = ndr_pull_struct_blob_all(
268 &in,
269 state,
270 &state->auth_rep,
271 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
273 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
274 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
275 ndr_map_error2string(ndr_err)));
276 tevent_req_error(req, EIO);
277 return;
280 if (DEBUGLVL(10)) {
281 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
284 if (state->auth_rep.length < 16) {
285 DEBUG(0, ("req invalid length: %u < 16\n",
286 state->auth_rep.length));
287 tevent_req_error(req, EIO);
288 return;
291 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
292 DEBUG(0, ("req invalid magic: %s != %s\n",
293 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
294 tevent_req_error(req, EIO);
295 return;
298 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
299 DEBUG(0, ("req failed: %s\n",
300 nt_errstr(state->auth_rep.status)));
301 tevent_req_error(req, EACCES);
302 return;
305 if (state->auth_rep.level != state->auth_req.level) {
306 DEBUG(0, ("req invalid level: %u != %u\n",
307 state->auth_rep.level, state->auth_req.level));
308 tevent_req_error(req, EIO);
309 return;
312 tevent_req_done(req);
315 int _tstream_npa_connect_recv(struct tevent_req *req,
316 int *perrno,
317 TALLOC_CTX *mem_ctx,
318 struct tstream_context **_stream,
319 uint16_t *_file_type,
320 uint16_t *_device_state,
321 uint64_t *_allocation_size,
322 const char *location)
324 struct tstream_npa_connect_state *state =
325 tevent_req_data(req,
326 struct tstream_npa_connect_state);
327 struct tstream_context *stream;
328 struct tstream_npa *npas;
329 uint16_t device_state = 0;
330 uint64_t allocation_size = 0;
332 if (tevent_req_is_unix_error(req, perrno)) {
333 tevent_req_received(req);
334 return -1;
337 stream = tstream_context_create(mem_ctx,
338 &tstream_npa_ops,
339 &npas,
340 struct tstream_npa,
341 location);
342 if (!stream) {
343 *perrno = ENOMEM;
344 tevent_req_received(req);
345 return -1;
347 ZERO_STRUCTP(npas);
349 npas->unix_stream = talloc_move(stream, &state->unix_stream);
350 switch (state->auth_rep.level) {
351 case 5:
352 npas->file_type = state->auth_rep.info.info5.file_type;
353 device_state = state->auth_rep.info.info5.device_state;
354 allocation_size = state->auth_rep.info.info5.allocation_size;
355 break;
358 *_stream = stream;
359 *_file_type = npas->file_type;
360 *_device_state = device_state;
361 *_allocation_size = allocation_size;
362 tevent_req_received(req);
363 return 0;
366 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
368 struct tstream_npa *npas = tstream_context_data(stream,
369 struct tstream_npa);
370 ssize_t ret;
372 if (!npas->unix_stream) {
373 errno = ENOTCONN;
374 return -1;
377 switch (npas->file_type) {
378 case FILE_TYPE_BYTE_MODE_PIPE:
379 ret = tstream_pending_bytes(npas->unix_stream);
380 break;
382 case FILE_TYPE_MESSAGE_MODE_PIPE:
383 ret = npas->pending.iov_len;
384 break;
386 default:
387 ret = -1;
390 return ret;
393 struct tstream_npa_readv_state {
394 struct tstream_context *stream;
396 struct iovec *vector;
397 size_t count;
399 /* the header for message mode */
400 uint8_t hdr[2];
401 bool wait_for_hdr;
403 int ret;
406 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
407 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
408 void *private_data,
409 TALLOC_CTX *mem_ctx,
410 struct iovec **_vector,
411 size_t *_count);
412 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
414 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
415 struct tevent_context *ev,
416 struct tstream_context *stream,
417 struct iovec *vector,
418 size_t count)
420 struct tevent_req *req;
421 struct tstream_npa_readv_state *state;
422 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
423 struct tevent_req *subreq;
424 off_t ofs;
425 size_t left;
426 uint8_t *pbase;
428 req = tevent_req_create(mem_ctx, &state,
429 struct tstream_npa_readv_state);
430 if (!req) {
431 return NULL;
434 state->stream = stream;
435 state->ret = 0;
437 if (!npas->unix_stream) {
438 tevent_req_error(req, ENOTCONN);
439 goto post;
442 switch (npas->file_type) {
443 case FILE_TYPE_BYTE_MODE_PIPE:
444 state->vector = vector;
445 state->count = count;
447 subreq = tstream_readv_send(state,
449 npas->unix_stream,
450 state->vector,
451 state->count);
452 if (tevent_req_nomem(subreq,req)) {
453 goto post;
455 tevent_req_set_callback(subreq,
456 tstream_npa_readv_byte_mode_handler,
457 req);
459 return req;
461 case FILE_TYPE_MESSAGE_MODE_PIPE:
463 * we make a copy of the vector and prepend a header
464 * with the length
466 state->vector = talloc_array(state, struct iovec, count);
467 if (tevent_req_nomem(state->vector, req)) {
468 goto post;
470 memcpy(state->vector, vector, sizeof(struct iovec)*count);
471 state->count = count;
474 * copy the pending buffer first
476 ofs = 0;
477 left = npas->pending.iov_len;
478 pbase = (uint8_t *)npas->pending.iov_base;
480 while (left > 0 && state->count > 0) {
481 uint8_t *base;
482 base = (uint8_t *)state->vector[0].iov_base;
483 if (left < state->vector[0].iov_len) {
484 memcpy(base, pbase + ofs, left);
486 base += left;
487 state->vector[0].iov_base = (char *) base;
488 state->vector[0].iov_len -= left;
490 ofs += left;
491 left = 0;
492 TALLOC_FREE(pbase);
493 ZERO_STRUCT(npas->pending);
494 break;
496 memcpy(base, pbase + ofs, state->vector[0].iov_len);
498 ofs += state->vector[0].iov_len;
499 left -= state->vector[0].iov_len;
500 state->vector += 1;
501 state->count -= 1;
503 if (left == 0) {
504 TALLOC_FREE(pbase);
505 ZERO_STRUCT(npas->pending);
506 break;
510 if (left > 0) {
511 memmove(pbase, pbase + ofs, left);
512 npas->pending.iov_base = (char *) pbase;
513 npas->pending.iov_len = left;
515 * this cannot fail and even if it
516 * fails we can handle it
518 pbase = talloc_realloc(npas, pbase, uint8_t, left);
519 if (pbase) {
520 npas->pending.iov_base = (char *) pbase;
522 pbase = NULL;
525 state->ret += ofs;
527 if (state->count == 0) {
528 tevent_req_done(req);
529 goto post;
532 ZERO_STRUCT(state->hdr);
533 state->wait_for_hdr = false;
535 subreq = tstream_readv_pdu_send(state,
537 npas->unix_stream,
538 tstream_npa_readv_next_vector,
539 state);
540 if (tevent_req_nomem(subreq, req)) {
541 goto post;
543 tevent_req_set_callback(subreq,
544 tstream_npa_readv_msg_mode_handler,
545 req);
547 return req;
550 /* this can't happen */
551 tevent_req_error(req, EINVAL);
552 goto post;
554 post:
555 tevent_req_post(req, ev);
556 return req;
559 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
561 struct tevent_req *req = tevent_req_callback_data(subreq,
562 struct tevent_req);
563 struct tstream_npa_readv_state *state = tevent_req_data(req,
564 struct tstream_npa_readv_state);
565 int ret;
566 int sys_errno;
568 ret = tstream_readv_recv(subreq, &sys_errno);
569 TALLOC_FREE(subreq);
570 if (ret == -1) {
571 tevent_req_error(req, sys_errno);
572 return;
575 state->ret = ret;
577 tevent_req_done(req);
580 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
581 void *private_data,
582 TALLOC_CTX *mem_ctx,
583 struct iovec **_vector,
584 size_t *_count)
586 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
587 struct tstream_npa_readv_state);
588 struct tstream_npa *npas = tstream_context_data(state->stream,
589 struct tstream_npa);
590 struct iovec *vector;
591 size_t count;
592 uint16_t msg_len;
593 size_t left;
595 if (state->count == 0) {
596 *_vector = NULL;
597 *_count = 0;
598 return 0;
601 if (!state->wait_for_hdr) {
602 /* we need to get a message header */
603 vector = talloc_array(mem_ctx, struct iovec, 1);
604 if (!vector) {
605 return -1;
607 ZERO_STRUCT(state->hdr);
608 vector[0].iov_base = (char *) state->hdr;
609 vector[0].iov_len = sizeof(state->hdr);
611 count = 1;
613 state->wait_for_hdr = true;
615 *_vector = vector;
616 *_count = count;
617 return 0;
620 /* and now fill the callers buffers and maybe the pending buffer */
621 state->wait_for_hdr = false;
623 msg_len = SVAL(state->hdr, 0);
625 if (msg_len == 0) {
626 errno = EIO;
627 return -1;
630 state->wait_for_hdr = false;
632 /* +1 because we may need to fill the pending buffer */
633 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
634 if (!vector) {
635 return -1;
638 count = 0;
639 left = msg_len;
640 while (left > 0 && state->count > 0) {
641 if (left < state->vector[0].iov_len) {
642 uint8_t *base;
643 base = (uint8_t *)state->vector[0].iov_base;
644 vector[count].iov_base = (char *) base;
645 vector[count].iov_len = left;
646 count++;
647 base += left;
648 state->vector[0].iov_base = (char *) base;
649 state->vector[0].iov_len -= left;
650 break;
652 vector[count] = state->vector[0];
653 count++;
654 left -= state->vector[0].iov_len;
655 state->vector += 1;
656 state->count -= 1;
659 if (left > 0) {
661 * if the message is longer than the buffers the caller
662 * requested, we need to consume the rest of the message
663 * into the pending buffer, where the next readv can
664 * be served from.
666 npas->pending.iov_base = talloc_array(npas, char, left);
667 if (!npas->pending.iov_base) {
668 return -1;
670 npas->pending.iov_len = left;
672 vector[count] = npas->pending;
673 count++;
676 state->ret += (msg_len - left);
678 *_vector = vector;
679 *_count = count;
680 return 0;
683 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
685 struct tevent_req *req = tevent_req_callback_data(subreq,
686 struct tevent_req);
687 int ret;
688 int sys_errno;
690 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
691 TALLOC_FREE(subreq);
692 if (ret == -1) {
693 tevent_req_error(req, sys_errno);
694 return;
698 * we do not set state->ret here as ret includes the header size.
699 * we set it in tstream_npa_readv_pdu_next_vector()
702 tevent_req_done(req);
705 static int tstream_npa_readv_recv(struct tevent_req *req,
706 int *perrno)
708 struct tstream_npa_readv_state *state = tevent_req_data(req,
709 struct tstream_npa_readv_state);
710 int ret;
712 ret = tsocket_simple_int_recv(req, perrno);
713 if (ret == 0) {
714 ret = state->ret;
717 tevent_req_received(req);
718 return ret;
721 struct tstream_npa_writev_state {
722 const struct iovec *vector;
723 size_t count;
725 /* the header for message mode */
726 bool hdr_used;
727 uint8_t hdr[2];
729 int ret;
732 static void tstream_npa_writev_handler(struct tevent_req *subreq);
734 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
735 struct tevent_context *ev,
736 struct tstream_context *stream,
737 const struct iovec *vector,
738 size_t count)
740 struct tevent_req *req;
741 struct tstream_npa_writev_state *state;
742 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
743 struct tevent_req *subreq;
744 size_t msg_len;
745 size_t i;
746 struct iovec *new_vector;
748 req = tevent_req_create(mem_ctx, &state,
749 struct tstream_npa_writev_state);
750 if (!req) {
751 return NULL;
754 state->ret = 0;
756 if (!npas->unix_stream) {
757 tevent_req_error(req, ENOTCONN);
758 goto post;
761 switch (npas->file_type) {
762 case FILE_TYPE_BYTE_MODE_PIPE:
763 state->hdr_used = false;
764 state->vector = vector;
765 state->count = count;
766 break;
768 case FILE_TYPE_MESSAGE_MODE_PIPE:
770 * we make a copy of the vector and prepend a header
771 * with the length
773 new_vector = talloc_array(state, struct iovec, count + 1);
774 if (tevent_req_nomem(new_vector, req)) {
775 goto post;
777 new_vector[0].iov_base = (char *) state->hdr;
778 new_vector[0].iov_len = sizeof(state->hdr);
779 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
781 state->hdr_used = true;
782 state->vector = new_vector;
783 state->count = count + 1;
785 msg_len = 0;
786 for (i=0; i < count; i++) {
788 * overflow check already done in tstream_writev_send
790 msg_len += vector[i].iov_len;
793 if (msg_len > UINT16_MAX) {
794 tevent_req_error(req, EMSGSIZE);
795 goto post;
798 SSVAL(state->hdr, 0, msg_len);
799 break;
802 subreq = tstream_writev_send(state,
804 npas->unix_stream,
805 state->vector,
806 state->count);
807 if (tevent_req_nomem(subreq, req)) {
808 goto post;
810 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
812 return req;
814 post:
815 tevent_req_post(req, ev);
816 return req;
819 static void tstream_npa_writev_handler(struct tevent_req *subreq)
821 struct tevent_req *req = tevent_req_callback_data(subreq,
822 struct tevent_req);
823 struct tstream_npa_writev_state *state = tevent_req_data(req,
824 struct tstream_npa_writev_state);
825 int ret;
826 int sys_errno;
828 ret = tstream_writev_recv(subreq, &sys_errno);
829 TALLOC_FREE(subreq);
830 if (ret == -1) {
831 tevent_req_error(req, sys_errno);
832 return;
836 * in message mode we need to hide the length
837 * of the hdr from the caller
839 if (state->hdr_used) {
840 ret -= sizeof(state->hdr);
843 state->ret = ret;
845 tevent_req_done(req);
848 static int tstream_npa_writev_recv(struct tevent_req *req,
849 int *perrno)
851 struct tstream_npa_writev_state *state = tevent_req_data(req,
852 struct tstream_npa_writev_state);
853 int ret;
855 ret = tsocket_simple_int_recv(req, perrno);
856 if (ret == 0) {
857 ret = state->ret;
860 tevent_req_received(req);
861 return ret;
864 struct tstream_npa_disconnect_state {
865 struct tstream_context *stream;
868 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
870 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
871 struct tevent_context *ev,
872 struct tstream_context *stream)
874 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
875 struct tevent_req *req;
876 struct tstream_npa_disconnect_state *state;
877 struct tevent_req *subreq;
879 req = tevent_req_create(mem_ctx, &state,
880 struct tstream_npa_disconnect_state);
881 if (req == NULL) {
882 return NULL;
885 state->stream = stream;
887 if (!npas->unix_stream) {
888 tevent_req_error(req, ENOTCONN);
889 goto post;
892 subreq = tstream_disconnect_send(state,
894 npas->unix_stream);
895 if (tevent_req_nomem(subreq, req)) {
896 goto post;
898 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
900 return req;
902 post:
903 tevent_req_post(req, ev);
904 return req;
907 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
909 struct tevent_req *req = tevent_req_callback_data(subreq,
910 struct tevent_req);
911 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
912 struct tstream_npa_disconnect_state);
913 struct tstream_context *stream = state->stream;
914 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
915 int ret;
916 int sys_errno;
918 ret = tstream_disconnect_recv(subreq, &sys_errno);
919 TALLOC_FREE(subreq);
920 if (ret == -1) {
921 tevent_req_error(req, sys_errno);
922 return;
925 TALLOC_FREE(npas->unix_stream);
927 tevent_req_done(req);
930 static int tstream_npa_disconnect_recv(struct tevent_req *req,
931 int *perrno)
933 int ret;
935 ret = tsocket_simple_int_recv(req, perrno);
937 tevent_req_received(req);
938 return ret;
941 static const struct tstream_context_ops tstream_npa_ops = {
942 .name = "npa",
944 .pending_bytes = tstream_npa_pending_bytes,
946 .readv_send = tstream_npa_readv_send,
947 .readv_recv = tstream_npa_readv_recv,
949 .writev_send = tstream_npa_writev_send,
950 .writev_recv = tstream_npa_writev_recv,
952 .disconnect_send = tstream_npa_disconnect_send,
953 .disconnect_recv = tstream_npa_disconnect_recv,
956 int _tstream_npa_existing_stream(TALLOC_CTX *mem_ctx,
957 struct tstream_context **transport,
958 uint16_t file_type,
959 struct tstream_context **_stream,
960 const char *location)
962 struct tstream_context *stream;
963 struct tstream_npa *npas;
965 switch (file_type) {
966 case FILE_TYPE_BYTE_MODE_PIPE:
967 break;
968 case FILE_TYPE_MESSAGE_MODE_PIPE:
969 break;
970 default:
971 errno = EINVAL;
972 return -1;
975 stream = tstream_context_create(mem_ctx,
976 &tstream_npa_ops,
977 &npas,
978 struct tstream_npa,
979 location);
980 if (!stream) {
981 return -1;
984 *npas = (struct tstream_npa) {
985 .file_type = file_type,
986 .unix_stream = talloc_move(npas, transport),
989 *_stream = stream;
990 return 0;
993 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
994 int fd,
995 uint16_t file_type,
996 struct tstream_context **_stream,
997 const char *location)
999 struct tstream_context *transport = NULL;
1000 int ret;
1002 ret = _tstream_bsd_existing_socket(
1003 mem_ctx, fd, &transport, location);
1004 if (ret == -1) {
1005 return -1;
1007 return _tstream_npa_existing_stream(
1008 mem_ctx, &transport, file_type, _stream, location);
1011 struct tstream_npa_accept_state {
1012 struct tevent_context *ev;
1013 struct tstream_context *plain;
1014 uint16_t file_type;
1015 uint16_t device_state;
1016 uint64_t alloc_size;
1018 struct named_pipe_auth_req *pipe_request;
1020 DATA_BLOB npa_blob;
1021 struct iovec out_iov;
1023 /* results */
1024 NTSTATUS accept_status;
1025 struct tsocket_address *remote_client_addr;
1026 struct tsocket_address *local_server_addr;
1029 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1030 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1032 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1033 struct tevent_context *ev,
1034 struct tstream_context *plain,
1035 uint16_t file_type,
1036 uint16_t device_state,
1037 uint64_t allocation_size)
1039 struct tstream_npa_accept_state *state;
1040 struct tevent_req *req, *subreq;
1042 req = tevent_req_create(mem_ctx, &state,
1043 struct tstream_npa_accept_state);
1044 if (req == NULL) {
1045 return NULL;
1048 switch (file_type) {
1049 case FILE_TYPE_BYTE_MODE_PIPE:
1050 break;
1051 case FILE_TYPE_MESSAGE_MODE_PIPE:
1052 break;
1053 default:
1054 tevent_req_error(req, EINVAL);
1055 goto post;
1058 state->ev = ev;
1059 state->plain = plain;
1060 state->file_type = file_type;
1061 state->device_state = device_state;
1062 state->alloc_size = allocation_size;
1064 subreq = tstream_u32_read_send(state, ev, 0x00FFFFFF, plain);
1065 if (tevent_req_nomem(subreq, req)) {
1066 goto post;
1069 tevent_req_set_callback(subreq,
1070 tstream_npa_accept_existing_reply, req);
1072 return req;
1074 post:
1075 tevent_req_post(req, ev);
1076 return req;
1079 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1081 struct tevent_req *req =
1082 tevent_req_callback_data(subreq, struct tevent_req);
1083 struct tstream_npa_accept_state *state =
1084 tevent_req_data(req, struct tstream_npa_accept_state);
1085 struct named_pipe_auth_req *pipe_request;
1086 struct named_pipe_auth_rep pipe_reply;
1087 struct named_pipe_auth_req_info5 i5;
1088 enum ndr_err_code ndr_err;
1089 DATA_BLOB in, out;
1090 int err;
1091 int ret;
1093 err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
1094 if (err != 0) {
1095 tevent_req_error(req, err);
1096 return;
1098 if (in.length < 8) {
1099 tevent_req_error(req, EMSGSIZE);
1100 return;
1103 if (memcmp(&in.data[4], NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1104 DBG_ERR("Wrong protocol\n");
1105 #if defined(EPROTONOSUPPORT)
1106 err = EPROTONOSUPPORT;
1107 #elif defined(EPROTO)
1108 err = EPROTO;
1109 #else
1110 err = EINVAL;
1111 #endif
1112 tevent_req_error(req, err);
1113 return;
1116 DBG_DEBUG("Received packet of length %zu\n", in.length);
1117 dump_data(11, in.data, in.length);
1119 ZERO_STRUCT(pipe_reply);
1120 pipe_reply.level = 0;
1121 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1123 * TODO: check it's a root (uid == 0) pipe
1126 pipe_request = talloc(state, struct named_pipe_auth_req);
1127 if (!pipe_request) {
1128 DEBUG(0, ("Out of memory!\n"));
1129 goto reply;
1131 state->pipe_request = pipe_request;
1133 /* parse the passed credentials */
1134 ndr_err = ndr_pull_struct_blob_all(
1135 &in,
1136 pipe_request,
1137 pipe_request,
1138 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1139 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1140 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1141 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1142 nt_errstr(pipe_reply.status)));
1143 goto reply;
1146 if (DEBUGLVL(10)) {
1147 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1150 ZERO_STRUCT(i5);
1152 if (pipe_request->level != 5) {
1153 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1154 pipe_reply.level = 0;
1155 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1156 goto reply;
1159 pipe_reply.level = 5;
1160 pipe_reply.status = NT_STATUS_OK;
1161 pipe_reply.info.info5.file_type = state->file_type;
1162 pipe_reply.info.info5.device_state = state->device_state;
1163 pipe_reply.info.info5.allocation_size = state->alloc_size;
1165 i5 = pipe_request->info.info5;
1166 if (i5.local_server_addr == NULL) {
1167 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1168 DEBUG(2, ("Missing local server address\n"));
1169 goto reply;
1171 if (i5.remote_client_addr == NULL) {
1172 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1173 DEBUG(2, ("Missing remote client address\n"));
1174 goto reply;
1177 ret = tsocket_address_inet_from_strings(state, "ip",
1178 i5.local_server_addr,
1179 i5.local_server_port,
1180 &state->local_server_addr);
1181 if (ret != 0) {
1182 DEBUG(2, ("Invalid local server address[%s:%u] - %s\n",
1183 i5.local_server_addr, i5.local_server_port,
1184 strerror(errno)));
1185 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1186 goto reply;
1189 ret = tsocket_address_inet_from_strings(state, "ip",
1190 i5.remote_client_addr,
1191 i5.remote_client_port,
1192 &state->remote_client_addr);
1193 if (ret != 0) {
1194 DEBUG(2, ("Invalid remote client address[%s:%u] - %s\n",
1195 i5.remote_client_addr, i5.remote_client_port,
1196 strerror(errno)));
1197 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1198 goto reply;
1201 reply:
1202 /* create the output */
1203 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1204 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1205 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1206 DEBUG(2, ("Error encoding structure: %s",
1207 ndr_map_error2string(ndr_err)));
1208 tevent_req_error(req, EIO);
1209 return;
1212 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1213 dump_data(11, out.data, out.length);
1215 if (DEBUGLVL(10)) {
1216 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1219 state->accept_status = pipe_reply.status;
1221 state->out_iov.iov_base = (char *) out.data;
1222 state->out_iov.iov_len = out.length;
1224 subreq = tstream_writev_send(state, state->ev,
1225 state->plain,
1226 &state->out_iov, 1);
1227 if (tevent_req_nomem(subreq, req)) {
1228 DEBUG(0, ("no memory for tstream_writev_send"));
1229 return;
1232 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1235 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1237 struct tevent_req *req =
1238 tevent_req_callback_data(subreq, struct tevent_req);
1239 int sys_errno;
1240 int ret;
1242 ret = tstream_writev_recv(subreq, &sys_errno);
1243 TALLOC_FREE(subreq);
1244 if (ret == -1) {
1245 tevent_req_error(req, sys_errno);
1246 return;
1249 tevent_req_done(req);
1252 static struct named_pipe_auth_req_info5 *copy_npa_info5(
1253 TALLOC_CTX *mem_ctx, const struct named_pipe_auth_req_info5 *src)
1255 struct named_pipe_auth_req_info5 *dst = NULL;
1256 DATA_BLOB blob;
1257 enum ndr_err_code ndr_err;
1259 dst = talloc_zero(mem_ctx, struct named_pipe_auth_req_info5);
1260 if (dst == NULL) {
1261 return NULL;
1264 ndr_err = ndr_push_struct_blob(
1265 &blob,
1266 dst,
1267 src,
1268 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req_info5);
1269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1270 DBG_WARNING("ndr_push_named_pipe_auth_req_info5 failed: %s\n",
1271 ndr_errstr(ndr_err));
1272 TALLOC_FREE(dst);
1273 return NULL;
1276 ndr_err = ndr_pull_struct_blob_all(
1277 &blob,
1278 dst,
1279 dst,
1280 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req_info5);
1281 TALLOC_FREE(blob.data);
1282 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1283 DBG_WARNING("ndr_push_named_pipe_auth_req_info5 failed: %s\n",
1284 ndr_errstr(ndr_err));
1285 TALLOC_FREE(dst);
1286 return NULL;
1289 return dst;
1292 int _tstream_npa_accept_existing_recv(
1293 struct tevent_req *req,
1294 int *perrno,
1295 TALLOC_CTX *mem_ctx,
1296 struct tstream_context **stream,
1297 struct named_pipe_auth_req_info5 **info5,
1298 enum dcerpc_transport_t *transport,
1299 struct tsocket_address **remote_client_addr,
1300 char **_remote_client_name,
1301 struct tsocket_address **local_server_addr,
1302 char **local_server_name,
1303 struct auth_session_info_transport **session_info,
1304 const char *location)
1306 struct tstream_npa_accept_state *state =
1307 tevent_req_data(req, struct tstream_npa_accept_state);
1308 struct named_pipe_auth_req_info5 *i5 = &state->pipe_request->info.info5;
1309 struct tstream_npa *npas;
1310 int ret;
1312 ret = tsocket_simple_int_recv(req, perrno);
1313 if (ret != 0) {
1314 DEBUG(2, ("Failed to accept named pipe connection: %s\n",
1315 strerror(*perrno)));
1316 tevent_req_received(req);
1317 return -1;
1320 if (!NT_STATUS_IS_OK(state->accept_status)) {
1321 #if defined(EPROTONOSUPPORT)
1322 *perrno = EPROTONOSUPPORT;
1323 #elif defined(EPROTO)
1324 *perrno = EPROTO;
1325 #else
1326 *perrno = EINVAL;
1327 #endif
1328 DEBUG(2, ("Failed to accept named pipe connection: %s => %s\n",
1329 nt_errstr(state->accept_status),
1330 strerror(*perrno)));
1331 tevent_req_received(req);
1332 return -1;
1335 *stream = tstream_context_create(mem_ctx,
1336 &tstream_npa_ops,
1337 &npas,
1338 struct tstream_npa,
1339 location);
1340 if (!*stream) {
1341 *perrno = ENOMEM;
1342 tevent_req_received(req);
1343 return -1;
1345 ZERO_STRUCTP(npas);
1346 npas->unix_stream = state->plain;
1347 npas->file_type = state->file_type;
1349 if (info5 != NULL) {
1351 * Make a full copy of "info5" because further down we
1352 * talloc_move() away substructures from
1353 * state->pipe_request.
1355 struct named_pipe_auth_req_info5 *dst = copy_npa_info5(
1356 mem_ctx, i5);
1357 if (dst == NULL) {
1358 *perrno = ENOMEM;
1359 tevent_req_received(req);
1360 return -1;
1362 *info5 = dst;
1365 if (transport != NULL) {
1366 *transport = i5->transport;
1368 if (remote_client_addr != NULL) {
1369 *remote_client_addr = talloc_move(
1370 mem_ctx, &state->remote_client_addr);
1372 if (_remote_client_name != NULL) {
1373 *_remote_client_name = discard_const_p(
1374 char, talloc_move(mem_ctx, &i5->remote_client_name));
1376 if (local_server_addr != NULL) {
1377 *local_server_addr = talloc_move(
1378 mem_ctx, &state->local_server_addr);
1380 if (local_server_name != NULL) {
1381 *local_server_name = discard_const_p(
1382 char, talloc_move(mem_ctx, &i5->local_server_name));
1384 if (session_info != NULL) {
1385 *session_info = talloc_move(mem_ctx, &i5->session_info);
1388 tevent_req_received(req);
1389 return 0;