ctdb-failover: Split statd_callout add-client/del-client
[Samba.git] / libcli / named_pipe_auth / npa_tstream.c
bloba72519e5da28b4cce7598f70dc18375ec8b5b15e
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_info8 *info8;
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 = 8;
123 info8 = &state->auth_req.info.info8;
125 info8->transport = transport;
126 SMB_ASSERT(info8->transport == transport); /* Assert no overflow */
128 info8->remote_client_name = remote_client_name_in;
129 info8->remote_client_addr =
130 tsocket_address_inet_addr_string(remote_client_addr, state);
131 if (!info8->remote_client_addr) {
132 /* errno might be EINVAL */
133 tevent_req_error(req, errno);
134 goto post;
136 info8->remote_client_port =
137 tsocket_address_inet_port(remote_client_addr);
138 if (!info8->remote_client_name) {
139 info8->remote_client_name = info8->remote_client_addr;
142 info8->local_server_name = local_server_name_in;
143 info8->local_server_addr =
144 tsocket_address_inet_addr_string(local_server_addr, state);
145 if (!info8->local_server_addr) {
146 /* errno might be EINVAL */
147 tevent_req_error(req, errno);
148 goto post;
150 info8->local_server_port =
151 tsocket_address_inet_port(local_server_addr);
152 if (!info8->local_server_name) {
153 info8->local_server_name = info8->local_server_addr;
156 info8->session_info =
157 discard_const_p(struct auth_session_info_transport,
158 session_info);
160 if (DEBUGLVL(10)) {
161 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
164 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
165 state, &state->auth_req,
166 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
167 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
168 tevent_req_error(req, EINVAL);
169 goto post;
172 state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
173 state->auth_req_iov.iov_len = state->auth_req_blob.length;
175 subreq = tstream_unix_connect_send(state,
176 state->caller.ev,
177 state->unix_laddr,
178 state->unix_raddr);
179 if (tevent_req_nomem(subreq, req)) {
180 goto post;
182 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
184 return req;
186 post:
187 tevent_req_post(req, ev);
188 return req;
191 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
193 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
195 struct tevent_req *req =
196 tevent_req_callback_data(subreq,
197 struct tevent_req);
198 struct tstream_npa_connect_state *state =
199 tevent_req_data(req,
200 struct tstream_npa_connect_state);
201 int ret;
202 int sys_errno;
204 ret = tstream_unix_connect_recv(subreq, &sys_errno,
205 state, &state->unix_stream);
206 TALLOC_FREE(subreq);
207 if (ret == -1) {
208 tevent_req_error(req, sys_errno);
209 return;
212 subreq = tstream_writev_send(state,
213 state->caller.ev,
214 state->unix_stream,
215 &state->auth_req_iov, 1);
216 if (tevent_req_nomem(subreq, req)) {
217 return;
219 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
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 subreq = tstream_u32_read_send(
243 state, state->caller.ev, 0x00FFFFFF, state->unix_stream);
244 if (tevent_req_nomem(subreq, req)) {
245 return;
247 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
250 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
252 struct tevent_req *req =
253 tevent_req_callback_data(subreq,
254 struct tevent_req);
255 struct tstream_npa_connect_state *state =
256 tevent_req_data(req,
257 struct tstream_npa_connect_state);
258 DATA_BLOB in;
259 int err;
260 enum ndr_err_code ndr_err;
262 err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
263 TALLOC_FREE(subreq);
264 if (tevent_req_error(req, err)) {
265 return;
268 DBG_DEBUG("name_pipe_auth_rep(client)[%zu]\n", in.length);
269 dump_data(11, in.data, in.length);
271 ndr_err = ndr_pull_struct_blob_all(
272 &in,
273 state,
274 &state->auth_rep,
275 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
278 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
279 ndr_map_error2string(ndr_err)));
280 tevent_req_error(req, EIO);
281 return;
284 if (DEBUGLVL(10)) {
285 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
288 if (state->auth_rep.length < 16) {
289 DEBUG(0, ("req invalid length: %u < 16\n",
290 state->auth_rep.length));
291 tevent_req_error(req, EIO);
292 return;
295 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
296 DEBUG(0, ("req invalid magic: %s != %s\n",
297 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
298 tevent_req_error(req, EIO);
299 return;
302 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
303 DEBUG(0, ("req failed: %s\n",
304 nt_errstr(state->auth_rep.status)));
305 tevent_req_error(req, EACCES);
306 return;
309 if (state->auth_rep.level != state->auth_req.level) {
310 DEBUG(0, ("req invalid level: %u != %u\n",
311 state->auth_rep.level, state->auth_req.level));
312 tevent_req_error(req, EIO);
313 return;
316 tevent_req_done(req);
319 int _tstream_npa_connect_recv(struct tevent_req *req,
320 int *perrno,
321 TALLOC_CTX *mem_ctx,
322 struct tstream_context **_stream,
323 uint16_t *_file_type,
324 uint16_t *_device_state,
325 uint64_t *_allocation_size,
326 const char *location)
328 struct tstream_npa_connect_state *state =
329 tevent_req_data(req,
330 struct tstream_npa_connect_state);
331 struct tstream_context *stream;
332 struct tstream_npa *npas;
333 uint16_t device_state = 0;
334 uint64_t allocation_size = 0;
336 if (tevent_req_is_unix_error(req, perrno)) {
337 tevent_req_received(req);
338 return -1;
341 stream = tstream_context_create(mem_ctx,
342 &tstream_npa_ops,
343 &npas,
344 struct tstream_npa,
345 location);
346 if (!stream) {
347 *perrno = ENOMEM;
348 tevent_req_received(req);
349 return -1;
351 ZERO_STRUCTP(npas);
353 npas->unix_stream = talloc_move(stream, &state->unix_stream);
354 switch (state->auth_rep.level) {
355 case 8:
356 npas->file_type = state->auth_rep.info.info8.file_type;
357 device_state = state->auth_rep.info.info8.device_state;
358 allocation_size = state->auth_rep.info.info8.allocation_size;
359 break;
362 *_stream = stream;
363 *_file_type = npas->file_type;
364 *_device_state = device_state;
365 *_allocation_size = allocation_size;
366 tevent_req_received(req);
367 return 0;
370 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
372 struct tstream_npa *npas = tstream_context_data(stream,
373 struct tstream_npa);
374 ssize_t ret;
376 if (!npas->unix_stream) {
377 errno = ENOTCONN;
378 return -1;
381 switch (npas->file_type) {
382 case FILE_TYPE_BYTE_MODE_PIPE:
383 ret = tstream_pending_bytes(npas->unix_stream);
384 break;
386 case FILE_TYPE_MESSAGE_MODE_PIPE:
387 ret = npas->pending.iov_len;
388 break;
390 default:
391 ret = -1;
394 return ret;
397 struct tstream_npa_readv_state {
398 struct tstream_context *stream;
400 struct iovec *vector;
401 size_t count;
403 /* the header for message mode */
404 uint8_t hdr[2];
405 bool wait_for_hdr;
407 int ret;
410 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
411 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
412 void *private_data,
413 TALLOC_CTX *mem_ctx,
414 struct iovec **_vector,
415 size_t *_count);
416 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
418 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
419 struct tevent_context *ev,
420 struct tstream_context *stream,
421 struct iovec *vector,
422 size_t count)
424 struct tevent_req *req;
425 struct tstream_npa_readv_state *state;
426 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
427 struct tevent_req *subreq;
428 off_t ofs;
429 size_t left;
430 uint8_t *pbase;
432 req = tevent_req_create(mem_ctx, &state,
433 struct tstream_npa_readv_state);
434 if (!req) {
435 return NULL;
438 state->stream = stream;
439 state->ret = 0;
441 if (!npas->unix_stream) {
442 tevent_req_error(req, ENOTCONN);
443 goto post;
446 switch (npas->file_type) {
447 case FILE_TYPE_BYTE_MODE_PIPE:
448 state->vector = vector;
449 state->count = count;
451 subreq = tstream_readv_send(state,
453 npas->unix_stream,
454 state->vector,
455 state->count);
456 if (tevent_req_nomem(subreq,req)) {
457 goto post;
459 tevent_req_set_callback(subreq,
460 tstream_npa_readv_byte_mode_handler,
461 req);
463 return req;
465 case FILE_TYPE_MESSAGE_MODE_PIPE:
467 * we make a copy of the vector and prepend a header
468 * with the length
470 state->vector = talloc_array(state, struct iovec, count);
471 if (tevent_req_nomem(state->vector, req)) {
472 goto post;
474 memcpy(state->vector, vector, sizeof(struct iovec)*count);
475 state->count = count;
478 * copy the pending buffer first
480 ofs = 0;
481 left = npas->pending.iov_len;
482 pbase = (uint8_t *)npas->pending.iov_base;
484 while (left > 0 && state->count > 0) {
485 uint8_t *base;
486 base = (uint8_t *)state->vector[0].iov_base;
487 if (left < state->vector[0].iov_len) {
488 memcpy(base, pbase + ofs, left);
490 base += left;
491 state->vector[0].iov_base = (char *) base;
492 state->vector[0].iov_len -= left;
494 ofs += left;
495 left = 0;
496 TALLOC_FREE(pbase);
497 ZERO_STRUCT(npas->pending);
498 break;
500 memcpy(base, pbase + ofs, state->vector[0].iov_len);
502 ofs += state->vector[0].iov_len;
503 left -= state->vector[0].iov_len;
504 state->vector += 1;
505 state->count -= 1;
507 if (left == 0) {
508 TALLOC_FREE(pbase);
509 ZERO_STRUCT(npas->pending);
510 break;
514 if (left > 0) {
515 memmove(pbase, pbase + ofs, left);
516 npas->pending.iov_base = (char *) pbase;
517 npas->pending.iov_len = left;
519 * this cannot fail and even if it
520 * fails we can handle it
522 pbase = talloc_realloc(npas, pbase, uint8_t, left);
523 if (pbase) {
524 npas->pending.iov_base = (char *) pbase;
526 pbase = NULL;
529 state->ret += ofs;
531 if (state->count == 0) {
532 tevent_req_done(req);
533 goto post;
536 ZERO_STRUCT(state->hdr);
537 state->wait_for_hdr = false;
539 subreq = tstream_readv_pdu_send(state,
541 npas->unix_stream,
542 tstream_npa_readv_next_vector,
543 state);
544 if (tevent_req_nomem(subreq, req)) {
545 goto post;
547 tevent_req_set_callback(subreq,
548 tstream_npa_readv_msg_mode_handler,
549 req);
551 return req;
554 /* this can't happen */
555 tevent_req_error(req, EINVAL);
556 goto post;
558 post:
559 tevent_req_post(req, ev);
560 return req;
563 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
565 struct tevent_req *req = tevent_req_callback_data(subreq,
566 struct tevent_req);
567 struct tstream_npa_readv_state *state = tevent_req_data(req,
568 struct tstream_npa_readv_state);
569 int ret;
570 int sys_errno;
572 ret = tstream_readv_recv(subreq, &sys_errno);
573 TALLOC_FREE(subreq);
574 if (ret == -1) {
575 tevent_req_error(req, sys_errno);
576 return;
579 state->ret = ret;
581 tevent_req_done(req);
584 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
585 void *private_data,
586 TALLOC_CTX *mem_ctx,
587 struct iovec **_vector,
588 size_t *_count)
590 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
591 struct tstream_npa_readv_state);
592 struct tstream_npa *npas = tstream_context_data(state->stream,
593 struct tstream_npa);
594 struct iovec *vector;
595 size_t count;
596 uint16_t msg_len;
597 size_t left;
599 if (state->count == 0) {
600 *_vector = NULL;
601 *_count = 0;
602 return 0;
605 if (!state->wait_for_hdr) {
606 /* we need to get a message header */
607 vector = talloc_array(mem_ctx, struct iovec, 1);
608 if (!vector) {
609 return -1;
611 ZERO_STRUCT(state->hdr);
612 vector[0].iov_base = (char *) state->hdr;
613 vector[0].iov_len = sizeof(state->hdr);
615 count = 1;
617 state->wait_for_hdr = true;
619 *_vector = vector;
620 *_count = count;
621 return 0;
624 /* and now fill the callers buffers and maybe the pending buffer */
625 state->wait_for_hdr = false;
627 msg_len = SVAL(state->hdr, 0);
629 if (msg_len == 0) {
630 errno = EIO;
631 return -1;
634 state->wait_for_hdr = false;
636 /* +1 because we may need to fill the pending buffer */
637 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
638 if (!vector) {
639 return -1;
642 count = 0;
643 left = msg_len;
644 while (left > 0 && state->count > 0) {
645 if (left < state->vector[0].iov_len) {
646 uint8_t *base;
647 base = (uint8_t *)state->vector[0].iov_base;
648 vector[count].iov_base = (char *) base;
649 vector[count].iov_len = left;
650 count++;
651 base += left;
652 state->vector[0].iov_base = (char *) base;
653 state->vector[0].iov_len -= left;
654 break;
656 vector[count] = state->vector[0];
657 count++;
658 left -= state->vector[0].iov_len;
659 state->vector += 1;
660 state->count -= 1;
663 if (left > 0) {
665 * if the message is longer than the buffers the caller
666 * requested, we need to consume the rest of the message
667 * into the pending buffer, where the next readv can
668 * be served from.
670 npas->pending.iov_base = talloc_array(npas, char, left);
671 if (!npas->pending.iov_base) {
672 return -1;
674 npas->pending.iov_len = left;
676 vector[count] = npas->pending;
677 count++;
680 state->ret += (msg_len - left);
682 *_vector = vector;
683 *_count = count;
684 return 0;
687 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
689 struct tevent_req *req = tevent_req_callback_data(subreq,
690 struct tevent_req);
691 int ret;
692 int sys_errno;
694 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
695 TALLOC_FREE(subreq);
696 if (ret == -1) {
697 tevent_req_error(req, sys_errno);
698 return;
702 * we do not set state->ret here as ret includes the header size.
703 * we set it in tstream_npa_readv_pdu_next_vector()
706 tevent_req_done(req);
709 static int tstream_npa_readv_recv(struct tevent_req *req,
710 int *perrno)
712 struct tstream_npa_readv_state *state = tevent_req_data(req,
713 struct tstream_npa_readv_state);
714 int ret;
716 ret = tsocket_simple_int_recv(req, perrno);
717 if (ret == 0) {
718 ret = state->ret;
721 tevent_req_received(req);
722 return ret;
725 struct tstream_npa_writev_state {
726 const struct iovec *vector;
727 size_t count;
729 /* the header for message mode */
730 bool hdr_used;
731 uint8_t hdr[2];
733 int ret;
736 static void tstream_npa_writev_handler(struct tevent_req *subreq);
738 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
739 struct tevent_context *ev,
740 struct tstream_context *stream,
741 const struct iovec *vector,
742 size_t count)
744 struct tevent_req *req;
745 struct tstream_npa_writev_state *state;
746 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
747 struct tevent_req *subreq;
748 size_t msg_len;
749 size_t i;
750 struct iovec *new_vector;
752 req = tevent_req_create(mem_ctx, &state,
753 struct tstream_npa_writev_state);
754 if (!req) {
755 return NULL;
758 state->ret = 0;
760 if (!npas->unix_stream) {
761 tevent_req_error(req, ENOTCONN);
762 goto post;
765 switch (npas->file_type) {
766 case FILE_TYPE_BYTE_MODE_PIPE:
767 state->hdr_used = false;
768 state->vector = vector;
769 state->count = count;
770 break;
772 case FILE_TYPE_MESSAGE_MODE_PIPE:
774 * we make a copy of the vector and prepend a header
775 * with the length
777 new_vector = talloc_array(state, struct iovec, count + 1);
778 if (tevent_req_nomem(new_vector, req)) {
779 goto post;
781 new_vector[0].iov_base = (char *) state->hdr;
782 new_vector[0].iov_len = sizeof(state->hdr);
783 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
785 state->hdr_used = true;
786 state->vector = new_vector;
787 state->count = count + 1;
789 msg_len = 0;
790 for (i=0; i < count; i++) {
792 * overflow check already done in tstream_writev_send
794 msg_len += vector[i].iov_len;
797 if (msg_len > UINT16_MAX) {
798 tevent_req_error(req, EMSGSIZE);
799 goto post;
802 SSVAL(state->hdr, 0, msg_len);
803 break;
806 subreq = tstream_writev_send(state,
808 npas->unix_stream,
809 state->vector,
810 state->count);
811 if (tevent_req_nomem(subreq, req)) {
812 goto post;
814 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
816 return req;
818 post:
819 tevent_req_post(req, ev);
820 return req;
823 static void tstream_npa_writev_handler(struct tevent_req *subreq)
825 struct tevent_req *req = tevent_req_callback_data(subreq,
826 struct tevent_req);
827 struct tstream_npa_writev_state *state = tevent_req_data(req,
828 struct tstream_npa_writev_state);
829 int ret;
830 int sys_errno;
832 ret = tstream_writev_recv(subreq, &sys_errno);
833 TALLOC_FREE(subreq);
834 if (ret == -1) {
835 tevent_req_error(req, sys_errno);
836 return;
840 * in message mode we need to hide the length
841 * of the hdr from the caller
843 if (state->hdr_used) {
844 ret -= sizeof(state->hdr);
847 state->ret = ret;
849 tevent_req_done(req);
852 static int tstream_npa_writev_recv(struct tevent_req *req,
853 int *perrno)
855 struct tstream_npa_writev_state *state = tevent_req_data(req,
856 struct tstream_npa_writev_state);
857 int ret;
859 ret = tsocket_simple_int_recv(req, perrno);
860 if (ret == 0) {
861 ret = state->ret;
864 tevent_req_received(req);
865 return ret;
868 struct tstream_npa_disconnect_state {
869 struct tstream_context *stream;
872 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
874 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
875 struct tevent_context *ev,
876 struct tstream_context *stream)
878 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
879 struct tevent_req *req;
880 struct tstream_npa_disconnect_state *state;
881 struct tevent_req *subreq;
883 req = tevent_req_create(mem_ctx, &state,
884 struct tstream_npa_disconnect_state);
885 if (req == NULL) {
886 return NULL;
889 state->stream = stream;
891 if (!npas->unix_stream) {
892 tevent_req_error(req, ENOTCONN);
893 goto post;
896 subreq = tstream_disconnect_send(state,
898 npas->unix_stream);
899 if (tevent_req_nomem(subreq, req)) {
900 goto post;
902 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
904 return req;
906 post:
907 tevent_req_post(req, ev);
908 return req;
911 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
913 struct tevent_req *req = tevent_req_callback_data(subreq,
914 struct tevent_req);
915 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
916 struct tstream_npa_disconnect_state);
917 struct tstream_context *stream = state->stream;
918 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
919 int ret;
920 int sys_errno;
922 ret = tstream_disconnect_recv(subreq, &sys_errno);
923 TALLOC_FREE(subreq);
924 if (ret == -1) {
925 tevent_req_error(req, sys_errno);
926 return;
929 TALLOC_FREE(npas->unix_stream);
931 tevent_req_done(req);
934 static int tstream_npa_disconnect_recv(struct tevent_req *req,
935 int *perrno)
937 int ret;
939 ret = tsocket_simple_int_recv(req, perrno);
941 tevent_req_received(req);
942 return ret;
945 static const struct tstream_context_ops tstream_npa_ops = {
946 .name = "npa",
948 .pending_bytes = tstream_npa_pending_bytes,
950 .readv_send = tstream_npa_readv_send,
951 .readv_recv = tstream_npa_readv_recv,
953 .writev_send = tstream_npa_writev_send,
954 .writev_recv = tstream_npa_writev_recv,
956 .disconnect_send = tstream_npa_disconnect_send,
957 .disconnect_recv = tstream_npa_disconnect_recv,
960 int _tstream_npa_existing_stream(TALLOC_CTX *mem_ctx,
961 struct tstream_context **transport,
962 uint16_t file_type,
963 struct tstream_context **_stream,
964 const char *location)
966 struct tstream_context *stream;
967 struct tstream_npa *npas;
969 switch (file_type) {
970 case FILE_TYPE_BYTE_MODE_PIPE:
971 break;
972 case FILE_TYPE_MESSAGE_MODE_PIPE:
973 break;
974 default:
975 errno = EINVAL;
976 return -1;
979 stream = tstream_context_create(mem_ctx,
980 &tstream_npa_ops,
981 &npas,
982 struct tstream_npa,
983 location);
984 if (!stream) {
985 return -1;
988 *npas = (struct tstream_npa) {
989 .file_type = file_type,
990 .unix_stream = talloc_move(npas, transport),
993 *_stream = stream;
994 return 0;
997 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
998 int fd,
999 uint16_t file_type,
1000 struct tstream_context **_stream,
1001 const char *location)
1003 struct tstream_context *transport = NULL;
1004 int ret;
1006 ret = _tstream_bsd_existing_socket(
1007 mem_ctx, fd, &transport, location);
1008 if (ret == -1) {
1009 return -1;
1011 /* as server we want to fail early */
1012 tstream_bsd_fail_readv_first_error(transport, true);
1013 return _tstream_npa_existing_stream(
1014 mem_ctx, &transport, file_type, _stream, location);
1017 struct tstream_npa_accept_state {
1018 struct tevent_context *ev;
1019 struct tstream_context *plain;
1020 uint16_t file_type;
1021 uint16_t device_state;
1022 uint64_t alloc_size;
1024 struct named_pipe_auth_req *pipe_request;
1026 DATA_BLOB npa_blob;
1027 struct iovec out_iov;
1029 /* results */
1030 NTSTATUS accept_status;
1031 struct tsocket_address *remote_client_addr;
1032 struct tsocket_address *local_server_addr;
1035 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1036 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1038 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1039 struct tevent_context *ev,
1040 struct tstream_context *plain,
1041 uint16_t file_type,
1042 uint16_t device_state,
1043 uint64_t allocation_size)
1045 struct tstream_npa_accept_state *state;
1046 struct tevent_req *req, *subreq;
1048 req = tevent_req_create(mem_ctx, &state,
1049 struct tstream_npa_accept_state);
1050 if (req == NULL) {
1051 return NULL;
1054 switch (file_type) {
1055 case FILE_TYPE_BYTE_MODE_PIPE:
1056 break;
1057 case FILE_TYPE_MESSAGE_MODE_PIPE:
1058 break;
1059 default:
1060 tevent_req_error(req, EINVAL);
1061 goto post;
1064 state->ev = ev;
1065 state->plain = plain;
1066 state->file_type = file_type;
1067 state->device_state = device_state;
1068 state->alloc_size = allocation_size;
1070 subreq = tstream_u32_read_send(state, ev, 0x00FFFFFF, plain);
1071 if (tevent_req_nomem(subreq, req)) {
1072 goto post;
1075 tevent_req_set_callback(subreq,
1076 tstream_npa_accept_existing_reply, req);
1078 return req;
1080 post:
1081 tevent_req_post(req, ev);
1082 return req;
1085 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1087 struct tevent_req *req =
1088 tevent_req_callback_data(subreq, struct tevent_req);
1089 struct tstream_npa_accept_state *state =
1090 tevent_req_data(req, struct tstream_npa_accept_state);
1091 struct named_pipe_auth_req *pipe_request;
1092 struct named_pipe_auth_rep pipe_reply;
1093 struct named_pipe_auth_req_info8 i8;
1094 enum ndr_err_code ndr_err;
1095 DATA_BLOB in, out;
1096 int err;
1097 int ret;
1099 err = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
1100 if (err != 0) {
1101 tevent_req_error(req, err);
1102 return;
1104 if (in.length < 8) {
1105 tevent_req_error(req, EMSGSIZE);
1106 return;
1109 if (memcmp(&in.data[4], NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1110 DBG_ERR("Wrong protocol\n");
1111 #if defined(EPROTONOSUPPORT)
1112 err = EPROTONOSUPPORT;
1113 #elif defined(EPROTO)
1114 err = EPROTO;
1115 #else
1116 err = EINVAL;
1117 #endif
1118 tevent_req_error(req, err);
1119 return;
1122 DBG_DEBUG("Received packet of length %zu\n", in.length);
1123 dump_data(11, in.data, in.length);
1125 ZERO_STRUCT(pipe_reply);
1126 pipe_reply.level = 0;
1127 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1129 * TODO: check it's a root (uid == 0) pipe
1132 pipe_request = talloc(state, struct named_pipe_auth_req);
1133 if (!pipe_request) {
1134 DEBUG(0, ("Out of memory!\n"));
1135 goto reply;
1137 state->pipe_request = pipe_request;
1139 /* parse the passed credentials */
1140 ndr_err = ndr_pull_struct_blob_all(
1141 &in,
1142 pipe_request,
1143 pipe_request,
1144 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1145 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1146 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1147 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1148 nt_errstr(pipe_reply.status)));
1149 goto reply;
1152 if (DEBUGLVL(10)) {
1153 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1156 ZERO_STRUCT(i8);
1158 if (pipe_request->level != 8) {
1159 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1160 pipe_reply.level = 0;
1161 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1162 goto reply;
1165 pipe_reply.level = 8;
1166 pipe_reply.status = NT_STATUS_OK;
1167 pipe_reply.info.info8.file_type = state->file_type;
1168 pipe_reply.info.info8.device_state = state->device_state;
1169 pipe_reply.info.info8.allocation_size = state->alloc_size;
1171 i8 = pipe_request->info.info8;
1172 if (i8.local_server_addr == NULL) {
1173 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1174 DEBUG(2, ("Missing local server address\n"));
1175 goto reply;
1177 if (i8.remote_client_addr == NULL) {
1178 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1179 DEBUG(2, ("Missing remote client address\n"));
1180 goto reply;
1183 ret = tsocket_address_inet_from_strings(state,
1184 "ip",
1185 i8.local_server_addr,
1186 i8.local_server_port,
1187 &state->local_server_addr);
1188 if (ret != 0) {
1189 DEBUG(2,
1190 ("Invalid local server address[%s:%u] - %s\n",
1191 i8.local_server_addr,
1192 i8.local_server_port,
1193 strerror(errno)));
1194 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1195 goto reply;
1198 ret = tsocket_address_inet_from_strings(state,
1199 "ip",
1200 i8.remote_client_addr,
1201 i8.remote_client_port,
1202 &state->remote_client_addr);
1203 if (ret != 0) {
1204 DEBUG(2,
1205 ("Invalid remote client address[%s:%u] - %s\n",
1206 i8.remote_client_addr,
1207 i8.remote_client_port,
1208 strerror(errno)));
1209 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1210 goto reply;
1213 reply:
1214 /* create the output */
1215 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1216 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1217 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1218 DEBUG(2, ("Error encoding structure: %s\n",
1219 ndr_map_error2string(ndr_err)));
1220 tevent_req_error(req, EIO);
1221 return;
1224 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1225 dump_data(11, out.data, out.length);
1227 if (DEBUGLVL(10)) {
1228 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1231 state->accept_status = pipe_reply.status;
1233 state->out_iov.iov_base = (char *) out.data;
1234 state->out_iov.iov_len = out.length;
1236 subreq = tstream_writev_send(state, state->ev,
1237 state->plain,
1238 &state->out_iov, 1);
1239 if (tevent_req_nomem(subreq, req)) {
1240 DEBUG(0, ("no memory for tstream_writev_send\n"));
1241 return;
1244 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1247 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1249 struct tevent_req *req =
1250 tevent_req_callback_data(subreq, struct tevent_req);
1251 int sys_errno;
1252 int ret;
1254 ret = tstream_writev_recv(subreq, &sys_errno);
1255 TALLOC_FREE(subreq);
1256 if (ret == -1) {
1257 tevent_req_error(req, sys_errno);
1258 return;
1261 tevent_req_done(req);
1264 static struct named_pipe_auth_req_info8 *
1265 copy_npa_info8(TALLOC_CTX *mem_ctx,
1266 const struct named_pipe_auth_req_info8 *src)
1268 struct named_pipe_auth_req_info8 *dst = NULL;
1269 DATA_BLOB blob;
1270 enum ndr_err_code ndr_err;
1272 dst = talloc_zero(mem_ctx, struct named_pipe_auth_req_info8);
1273 if (dst == NULL) {
1274 return NULL;
1277 ndr_err = ndr_push_struct_blob(
1278 &blob,
1279 dst,
1280 src,
1281 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req_info8);
1282 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1283 DBG_WARNING("ndr_push_named_pipe_auth_req_info8 failed: %s\n",
1284 ndr_errstr(ndr_err));
1285 TALLOC_FREE(dst);
1286 return NULL;
1289 ndr_err = ndr_pull_struct_blob_all(
1290 &blob,
1291 dst,
1292 dst,
1293 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req_info8);
1294 TALLOC_FREE(blob.data);
1295 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1296 DBG_WARNING("ndr_push_named_pipe_auth_req_info8 failed: %s\n",
1297 ndr_errstr(ndr_err));
1298 TALLOC_FREE(dst);
1299 return NULL;
1302 return dst;
1305 int _tstream_npa_accept_existing_recv(
1306 struct tevent_req *req,
1307 int *perrno,
1308 TALLOC_CTX *mem_ctx,
1309 struct tstream_context **stream,
1310 struct named_pipe_auth_req_info8 **info8,
1311 enum dcerpc_transport_t *transport,
1312 struct tsocket_address **remote_client_addr,
1313 char **_remote_client_name,
1314 struct tsocket_address **local_server_addr,
1315 char **local_server_name,
1316 struct auth_session_info_transport **session_info,
1317 const char *location)
1319 struct tstream_npa_accept_state *state =
1320 tevent_req_data(req, struct tstream_npa_accept_state);
1321 struct named_pipe_auth_req_info8 *i8 =
1322 &state->pipe_request->info.info8;
1323 struct tstream_npa *npas;
1324 int ret;
1326 ret = tsocket_simple_int_recv(req, perrno);
1327 if (ret != 0) {
1328 DEBUG(2, ("Failed to accept named pipe connection: %s\n",
1329 strerror(*perrno)));
1330 tevent_req_received(req);
1331 return -1;
1334 if (!NT_STATUS_IS_OK(state->accept_status)) {
1335 #if defined(EPROTONOSUPPORT)
1336 *perrno = EPROTONOSUPPORT;
1337 #elif defined(EPROTO)
1338 *perrno = EPROTO;
1339 #else
1340 *perrno = EINVAL;
1341 #endif
1342 DEBUG(2, ("Failed to accept named pipe connection: %s => %s\n",
1343 nt_errstr(state->accept_status),
1344 strerror(*perrno)));
1345 tevent_req_received(req);
1346 return -1;
1349 *stream = tstream_context_create(mem_ctx,
1350 &tstream_npa_ops,
1351 &npas,
1352 struct tstream_npa,
1353 location);
1354 if (!*stream) {
1355 *perrno = ENOMEM;
1356 tevent_req_received(req);
1357 return -1;
1359 ZERO_STRUCTP(npas);
1360 npas->unix_stream = state->plain;
1361 npas->file_type = state->file_type;
1363 if (info8 != NULL) {
1365 * Make a full copy of "info8" because further down we
1366 * talloc_move() away substructures from
1367 * state->pipe_request.
1369 struct named_pipe_auth_req_info8 *dst =
1370 copy_npa_info8(mem_ctx, i8);
1371 if (dst == NULL) {
1372 *perrno = ENOMEM;
1373 tevent_req_received(req);
1374 return -1;
1376 *info8 = dst;
1379 if (transport != NULL) {
1380 *transport = i8->transport;
1382 if (remote_client_addr != NULL) {
1383 *remote_client_addr = talloc_move(
1384 mem_ctx, &state->remote_client_addr);
1386 if (_remote_client_name != NULL) {
1387 *_remote_client_name = discard_const_p(
1388 char,
1389 talloc_move(mem_ctx, &i8->remote_client_name));
1391 if (local_server_addr != NULL) {
1392 *local_server_addr = talloc_move(
1393 mem_ctx, &state->local_server_addr);
1395 if (local_server_name != NULL) {
1396 *local_server_name = discard_const_p(
1397 char,
1398 talloc_move(mem_ctx, &i8->local_server_name));
1400 if (session_info != NULL) {
1401 *session_info = talloc_move(mem_ctx, &i8->session_info);
1404 tevent_req_received(req);
1405 return 0;