waf: Fix bug #8801 - build s3fs manpages.
[Samba/gebeck_regimport.git] / libcli / named_pipe_auth / npa_tstream.c
blobc2eb7bf7148d73f14992e9dcd0ad46f2d5bd3abf
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/smb/smb_constants.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 } caller;
44 const char *unix_path;
45 struct tsocket_address *unix_laddr;
46 struct tsocket_address *unix_raddr;
47 struct tstream_context *unix_stream;
49 struct named_pipe_auth_req auth_req;
50 DATA_BLOB auth_req_blob;
51 struct iovec auth_req_iov;
53 struct named_pipe_auth_rep auth_rep;
54 DATA_BLOB auth_rep_blob;
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 const struct tsocket_address *client,
64 const char *client_name_in,
65 const struct tsocket_address *server,
66 const char *server_name,
67 const struct auth_session_info_transport *session_info)
69 struct tevent_req *req;
70 struct tstream_npa_connect_state *state;
71 struct tevent_req *subreq;
72 int ret;
73 enum ndr_err_code ndr_err;
74 char *lower_case_npipe;
75 struct named_pipe_auth_req_info4 *info4;
77 req = tevent_req_create(mem_ctx, &state,
78 struct tstream_npa_connect_state);
79 if (!req) {
80 return NULL;
83 state->caller.ev = ev;
85 lower_case_npipe = strlower_talloc(state, npipe);
86 if (tevent_req_nomem(lower_case_npipe, req)) {
87 goto post;
90 state->unix_path = talloc_asprintf(state, "%s/%s",
91 directory,
92 lower_case_npipe);
93 talloc_free(lower_case_npipe);
94 if (tevent_req_nomem(state->unix_path, req)) {
95 goto post;
98 ret = tsocket_address_unix_from_path(state,
99 "",
100 &state->unix_laddr);
101 if (ret == -1) {
102 tevent_req_error(req, errno);
103 goto post;
106 ret = tsocket_address_unix_from_path(state,
107 state->unix_path,
108 &state->unix_raddr);
109 if (ret == -1) {
110 tevent_req_error(req, errno);
111 goto post;
114 ZERO_STRUCT(state->auth_req);
116 if (!server) {
117 tevent_req_error(req, EINVAL);
118 goto post;
121 state->auth_req.level = 4;
122 info4 = &state->auth_req.info.info4;
124 info4->client_name = client_name_in;
125 info4->client_addr = tsocket_address_inet_addr_string(client, state);
126 if (!info4->client_addr) {
127 /* errno might be EINVAL */
128 tevent_req_error(req, errno);
129 goto post;
131 info4->client_port = tsocket_address_inet_port(client);
132 if (!info4->client_name) {
133 info4->client_name = info4->client_addr;
136 info4->server_addr = tsocket_address_inet_addr_string(server, state);
137 if (!info4->server_addr) {
138 /* errno might be EINVAL */
139 tevent_req_error(req, errno);
140 goto post;
142 info4->server_port = tsocket_address_inet_port(server);
143 if (!info4->server_name) {
144 info4->server_name = info4->server_addr;
147 info4->session_info = discard_const_p(struct auth_session_info_transport, session_info);
149 if (DEBUGLVL(10)) {
150 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
153 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
154 state, &state->auth_req,
155 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157 tevent_req_error(req, EINVAL);
158 goto post;
161 state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
162 state->auth_req_iov.iov_len = state->auth_req_blob.length;
164 subreq = tstream_unix_connect_send(state,
165 state->caller.ev,
166 state->unix_laddr,
167 state->unix_raddr);
168 if (tevent_req_nomem(subreq, req)) {
169 goto post;
171 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
173 return req;
175 post:
176 tevent_req_post(req, ev);
177 return req;
180 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
182 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
184 struct tevent_req *req =
185 tevent_req_callback_data(subreq,
186 struct tevent_req);
187 struct tstream_npa_connect_state *state =
188 tevent_req_data(req,
189 struct tstream_npa_connect_state);
190 int ret;
191 int sys_errno;
193 ret = tstream_unix_connect_recv(subreq, &sys_errno,
194 state, &state->unix_stream);
195 TALLOC_FREE(subreq);
196 if (ret == -1) {
197 tevent_req_error(req, sys_errno);
198 return;
201 subreq = tstream_writev_send(state,
202 state->caller.ev,
203 state->unix_stream,
204 &state->auth_req_iov, 1);
205 if (tevent_req_nomem(subreq, req)) {
206 return;
208 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
211 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
212 void *private_data,
213 TALLOC_CTX *mem_ctx,
214 struct iovec **_vector,
215 size_t *_count);
216 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
218 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
220 struct tevent_req *req =
221 tevent_req_callback_data(subreq,
222 struct tevent_req);
223 struct tstream_npa_connect_state *state =
224 tevent_req_data(req,
225 struct tstream_npa_connect_state);
226 int ret;
227 int sys_errno;
229 ret = tstream_writev_recv(subreq, &sys_errno);
230 TALLOC_FREE(subreq);
231 if (ret == -1) {
232 tevent_req_error(req, sys_errno);
233 return;
236 state->auth_rep_blob = data_blob_const(NULL, 0);
238 subreq = tstream_readv_pdu_send(state, state->caller.ev,
239 state->unix_stream,
240 tstream_npa_connect_next_vector,
241 state);
242 if (tevent_req_nomem(subreq, req)) {
243 return;
245 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
248 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
249 void *private_data,
250 TALLOC_CTX *mem_ctx,
251 struct iovec **_vector,
252 size_t *_count)
254 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
255 struct tstream_npa_connect_state);
256 struct iovec *vector;
257 size_t count;
258 off_t ofs = 0;
260 if (state->auth_rep_blob.length == 0) {
261 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
262 if (!state->auth_rep_blob.data) {
263 return -1;
265 } else if (state->auth_rep_blob.length == 4) {
266 uint32_t msg_len;
268 ofs = 4;
270 msg_len = RIVAL(state->auth_rep_blob.data, 0);
272 if (msg_len > 0x00FFFFFF) {
273 errno = EMSGSIZE;
274 return -1;
277 if (msg_len == 0) {
278 errno = EMSGSIZE;
279 return -1;
282 msg_len += ofs;
284 state->auth_rep_blob.data = talloc_realloc(state,
285 state->auth_rep_blob.data,
286 uint8_t, msg_len);
287 if (!state->auth_rep_blob.data) {
288 return -1;
290 state->auth_rep_blob.length = msg_len;
291 } else {
292 *_vector = NULL;
293 *_count = 0;
294 return 0;
297 /* we need to get a message header */
298 vector = talloc_array(mem_ctx, struct iovec, 1);
299 if (!vector) {
300 return -1;
302 vector[0].iov_base = (char *) (state->auth_rep_blob.data + ofs);
303 vector[0].iov_len = state->auth_rep_blob.length - ofs;
304 count = 1;
306 *_vector = vector;
307 *_count = count;
308 return 0;
311 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
313 struct tevent_req *req =
314 tevent_req_callback_data(subreq,
315 struct tevent_req);
316 struct tstream_npa_connect_state *state =
317 tevent_req_data(req,
318 struct tstream_npa_connect_state);
319 int ret;
320 int sys_errno;
321 enum ndr_err_code ndr_err;
323 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
324 TALLOC_FREE(subreq);
325 if (ret == -1) {
326 tevent_req_error(req, sys_errno);
327 return;
330 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
331 (uint32_t)state->auth_rep_blob.length));
332 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
334 ndr_err = ndr_pull_struct_blob(
335 &state->auth_rep_blob, state,
336 &state->auth_rep,
337 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
339 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
340 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
341 ndr_map_error2string(ndr_err)));
342 tevent_req_error(req, EIO);
343 return;
346 if (DEBUGLVL(10)) {
347 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
350 if (state->auth_rep.length < 16) {
351 DEBUG(0, ("req invalid length: %u < 16\n",
352 state->auth_rep.length));
353 tevent_req_error(req, EIO);
354 return;
357 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
358 DEBUG(0, ("req invalid magic: %s != %s\n",
359 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
360 tevent_req_error(req, EIO);
361 return;
364 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
365 DEBUG(0, ("req failed: %s\n",
366 nt_errstr(state->auth_rep.status)));
367 tevent_req_error(req, EACCES);
368 return;
371 if (state->auth_rep.level != state->auth_req.level) {
372 DEBUG(0, ("req invalid level: %u != %u\n",
373 state->auth_rep.level, state->auth_req.level));
374 tevent_req_error(req, EIO);
375 return;
378 tevent_req_done(req);
381 int _tstream_npa_connect_recv(struct tevent_req *req,
382 int *perrno,
383 TALLOC_CTX *mem_ctx,
384 struct tstream_context **_stream,
385 uint16_t *_file_type,
386 uint16_t *_device_state,
387 uint64_t *_allocation_size,
388 const char *location)
390 struct tstream_npa_connect_state *state =
391 tevent_req_data(req,
392 struct tstream_npa_connect_state);
393 struct tstream_context *stream;
394 struct tstream_npa *npas;
395 uint16_t device_state = 0;
396 uint64_t allocation_size = 0;
398 if (tevent_req_is_unix_error(req, perrno)) {
399 tevent_req_received(req);
400 return -1;
403 stream = tstream_context_create(mem_ctx,
404 &tstream_npa_ops,
405 &npas,
406 struct tstream_npa,
407 location);
408 if (!stream) {
409 *perrno = ENOMEM;
410 tevent_req_received(req);
411 return -1;
413 ZERO_STRUCTP(npas);
415 npas->unix_stream = talloc_move(stream, &state->unix_stream);
416 switch (state->auth_rep.level) {
417 case 4:
418 npas->file_type = state->auth_rep.info.info4.file_type;
419 device_state = state->auth_rep.info.info4.device_state;
420 allocation_size = state->auth_rep.info.info4.allocation_size;
421 break;
424 *_stream = stream;
425 *_file_type = npas->file_type;
426 *_device_state = device_state;
427 *_allocation_size = allocation_size;
428 tevent_req_received(req);
429 return 0;
432 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
434 struct tstream_npa *npas = tstream_context_data(stream,
435 struct tstream_npa);
436 ssize_t ret;
438 if (!npas->unix_stream) {
439 errno = ENOTCONN;
440 return -1;
443 switch (npas->file_type) {
444 case FILE_TYPE_BYTE_MODE_PIPE:
445 ret = tstream_pending_bytes(npas->unix_stream);
446 break;
448 case FILE_TYPE_MESSAGE_MODE_PIPE:
449 ret = npas->pending.iov_len;
450 break;
452 default:
453 ret = -1;
456 return ret;
459 struct tstream_npa_readv_state {
460 struct tstream_context *stream;
462 struct iovec *vector;
463 size_t count;
465 /* the header for message mode */
466 uint8_t hdr[2];
467 bool wait_for_hdr;
469 int ret;
472 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
473 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
474 void *private_data,
475 TALLOC_CTX *mem_ctx,
476 struct iovec **_vector,
477 size_t *_count);
478 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
480 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
481 struct tevent_context *ev,
482 struct tstream_context *stream,
483 struct iovec *vector,
484 size_t count)
486 struct tevent_req *req;
487 struct tstream_npa_readv_state *state;
488 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
489 struct tevent_req *subreq;
490 off_t ofs;
491 size_t left;
492 uint8_t *pbase;
494 req = tevent_req_create(mem_ctx, &state,
495 struct tstream_npa_readv_state);
496 if (!req) {
497 return NULL;
500 state->stream = stream;
501 state->ret = 0;
503 if (!npas->unix_stream) {
504 tevent_req_error(req, ENOTCONN);
505 goto post;
508 switch (npas->file_type) {
509 case FILE_TYPE_BYTE_MODE_PIPE:
510 state->vector = vector;
511 state->count = count;
513 subreq = tstream_readv_send(state,
515 npas->unix_stream,
516 state->vector,
517 state->count);
518 if (tevent_req_nomem(subreq,req)) {
519 goto post;
521 tevent_req_set_callback(subreq,
522 tstream_npa_readv_byte_mode_handler,
523 req);
525 return req;
527 case FILE_TYPE_MESSAGE_MODE_PIPE:
529 * we make a copy of the vector and prepend a header
530 * with the length
532 state->vector = talloc_array(state, struct iovec, count);
533 if (tevent_req_nomem(state->vector, req)) {
534 goto post;
536 memcpy(state->vector, vector, sizeof(struct iovec)*count);
537 state->count = count;
540 * copy the pending buffer first
542 ofs = 0;
543 left = npas->pending.iov_len;
544 pbase = (uint8_t *)npas->pending.iov_base;
546 while (left > 0 && state->count > 0) {
547 uint8_t *base;
548 base = (uint8_t *)state->vector[0].iov_base;
549 if (left < state->vector[0].iov_len) {
550 memcpy(base, pbase + ofs, left);
552 base += left;
553 state->vector[0].iov_base = (char *) base;
554 state->vector[0].iov_len -= left;
556 ofs += left;
557 left = 0;
558 TALLOC_FREE(pbase);
559 ZERO_STRUCT(npas->pending);
560 break;
562 memcpy(base, pbase + ofs, state->vector[0].iov_len);
564 ofs += state->vector[0].iov_len;
565 left -= state->vector[0].iov_len;
566 state->vector += 1;
567 state->count -= 1;
569 if (left == 0) {
570 TALLOC_FREE(pbase);
571 ZERO_STRUCT(npas->pending);
572 break;
576 if (left > 0) {
577 memmove(pbase, pbase + ofs, left);
578 npas->pending.iov_base = (char *) pbase;
579 npas->pending.iov_len = left;
581 * this cannot fail and even if it
582 * fails we can handle it
584 pbase = talloc_realloc(npas, pbase, uint8_t, left);
585 if (pbase) {
586 npas->pending.iov_base = (char *) pbase;
588 pbase = NULL;
591 state->ret += ofs;
593 if (state->count == 0) {
594 tevent_req_done(req);
595 goto post;
598 ZERO_STRUCT(state->hdr);
599 state->wait_for_hdr = false;
601 subreq = tstream_readv_pdu_send(state,
603 npas->unix_stream,
604 tstream_npa_readv_next_vector,
605 state);
606 if (tevent_req_nomem(subreq, req)) {
607 goto post;
609 tevent_req_set_callback(subreq,
610 tstream_npa_readv_msg_mode_handler,
611 req);
613 return req;
616 /* this can't happen */
617 tevent_req_error(req, EINVAL);
618 goto post;
620 post:
621 tevent_req_post(req, ev);
622 return req;
625 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
627 struct tevent_req *req = tevent_req_callback_data(subreq,
628 struct tevent_req);
629 struct tstream_npa_readv_state *state = tevent_req_data(req,
630 struct tstream_npa_readv_state);
631 int ret;
632 int sys_errno;
634 ret = tstream_readv_recv(subreq, &sys_errno);
635 TALLOC_FREE(subreq);
636 if (ret == -1) {
637 tevent_req_error(req, sys_errno);
638 return;
641 state->ret = ret;
643 tevent_req_done(req);
646 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
647 void *private_data,
648 TALLOC_CTX *mem_ctx,
649 struct iovec **_vector,
650 size_t *_count)
652 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
653 struct tstream_npa_readv_state);
654 struct tstream_npa *npas = tstream_context_data(state->stream,
655 struct tstream_npa);
656 struct iovec *vector;
657 size_t count;
658 uint16_t msg_len;
659 size_t left;
661 if (state->count == 0) {
662 *_vector = NULL;
663 *_count = 0;
664 return 0;
667 if (!state->wait_for_hdr) {
668 /* we need to get a message header */
669 vector = talloc_array(mem_ctx, struct iovec, 1);
670 if (!vector) {
671 return -1;
673 ZERO_STRUCT(state->hdr);
674 vector[0].iov_base = (char *) state->hdr;
675 vector[0].iov_len = sizeof(state->hdr);
677 count = 1;
679 state->wait_for_hdr = true;
681 *_vector = vector;
682 *_count = count;
683 return 0;
686 /* and now fill the callers buffers and maybe the pending buffer */
687 state->wait_for_hdr = false;
689 msg_len = SVAL(state->hdr, 0);
691 if (msg_len == 0) {
692 errno = EIO;
693 return -1;
696 state->wait_for_hdr = false;
698 /* +1 because we may need to fill the pending buffer */
699 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
700 if (!vector) {
701 return -1;
704 count = 0;
705 left = msg_len;
706 while (left > 0 && state->count > 0) {
707 if (left < state->vector[0].iov_len) {
708 uint8_t *base;
709 base = (uint8_t *)state->vector[0].iov_base;
710 vector[count].iov_base = (char *) base;
711 vector[count].iov_len = left;
712 count++;
713 base += left;
714 state->vector[0].iov_base = (char *) base;
715 state->vector[0].iov_len -= left;
716 break;
718 vector[count] = state->vector[0];
719 count++;
720 left -= state->vector[0].iov_len;
721 state->vector += 1;
722 state->count -= 1;
725 if (left > 0) {
727 * if the message is longer than the buffers the caller
728 * requested, we need to consume the rest of the message
729 * into the pending buffer, where the next readv can
730 * be served from.
732 npas->pending.iov_base = talloc_array(npas, char, left);
733 if (!npas->pending.iov_base) {
734 return -1;
736 npas->pending.iov_len = left;
738 vector[count] = npas->pending;
739 count++;
742 state->ret += (msg_len - left);
744 *_vector = vector;
745 *_count = count;
746 return 0;
749 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
751 struct tevent_req *req = tevent_req_callback_data(subreq,
752 struct tevent_req);
753 int ret;
754 int sys_errno;
756 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
757 TALLOC_FREE(subreq);
758 if (ret == -1) {
759 tevent_req_error(req, sys_errno);
760 return;
764 * we do not set state->ret here as ret includes the headr size.
765 * we set it in tstream_npa_readv_pdu_next_vector()
768 tevent_req_done(req);
771 static int tstream_npa_readv_recv(struct tevent_req *req,
772 int *perrno)
774 struct tstream_npa_readv_state *state = tevent_req_data(req,
775 struct tstream_npa_readv_state);
776 int ret;
778 ret = tsocket_simple_int_recv(req, perrno);
779 if (ret == 0) {
780 ret = state->ret;
783 tevent_req_received(req);
784 return ret;
787 struct tstream_npa_writev_state {
788 const struct iovec *vector;
789 size_t count;
791 /* the header for message mode */
792 bool hdr_used;
793 uint8_t hdr[2];
795 int ret;
798 static void tstream_npa_writev_handler(struct tevent_req *subreq);
800 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
801 struct tevent_context *ev,
802 struct tstream_context *stream,
803 const struct iovec *vector,
804 size_t count)
806 struct tevent_req *req;
807 struct tstream_npa_writev_state *state;
808 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
809 struct tevent_req *subreq;
810 size_t msg_len;
811 size_t i;
812 struct iovec *new_vector;
814 req = tevent_req_create(mem_ctx, &state,
815 struct tstream_npa_writev_state);
816 if (!req) {
817 return NULL;
820 state->ret = 0;
822 if (!npas->unix_stream) {
823 tevent_req_error(req, ENOTCONN);
824 goto post;
827 switch (npas->file_type) {
828 case FILE_TYPE_BYTE_MODE_PIPE:
829 state->hdr_used = false;
830 state->vector = vector;
831 state->count = count;
832 break;
834 case FILE_TYPE_MESSAGE_MODE_PIPE:
836 * we make a copy of the vector and prepend a header
837 * with the length
839 new_vector = talloc_array(state, struct iovec, count + 1);
840 if (tevent_req_nomem(new_vector, req)) {
841 goto post;
843 new_vector[0].iov_base = (char *) state->hdr;
844 new_vector[0].iov_len = sizeof(state->hdr);
845 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
847 state->hdr_used = true;
848 state->vector = new_vector;
849 state->count = count + 1;
851 msg_len = 0;
852 for (i=0; i < count; i++) {
853 msg_len += vector[i].iov_len;
856 if (msg_len > UINT16_MAX) {
857 tevent_req_error(req, EMSGSIZE);
858 goto post;
861 SSVAL(state->hdr, 0, msg_len);
862 break;
865 subreq = tstream_writev_send(state,
867 npas->unix_stream,
868 state->vector,
869 state->count);
870 if (tevent_req_nomem(subreq, req)) {
871 goto post;
873 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
875 return req;
877 post:
878 tevent_req_post(req, ev);
879 return req;
882 static void tstream_npa_writev_handler(struct tevent_req *subreq)
884 struct tevent_req *req = tevent_req_callback_data(subreq,
885 struct tevent_req);
886 struct tstream_npa_writev_state *state = tevent_req_data(req,
887 struct tstream_npa_writev_state);
888 int ret;
889 int sys_errno;
891 ret = tstream_writev_recv(subreq, &sys_errno);
892 TALLOC_FREE(subreq);
893 if (ret == -1) {
894 tevent_req_error(req, sys_errno);
895 return;
899 * in message mode we need to hide the length
900 * of the hdr from the caller
902 if (state->hdr_used) {
903 ret -= sizeof(state->hdr);
906 state->ret = ret;
908 tevent_req_done(req);
911 static int tstream_npa_writev_recv(struct tevent_req *req,
912 int *perrno)
914 struct tstream_npa_writev_state *state = tevent_req_data(req,
915 struct tstream_npa_writev_state);
916 int ret;
918 ret = tsocket_simple_int_recv(req, perrno);
919 if (ret == 0) {
920 ret = state->ret;
923 tevent_req_received(req);
924 return ret;
927 struct tstream_npa_disconnect_state {
928 struct tstream_context *stream;
931 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
933 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
934 struct tevent_context *ev,
935 struct tstream_context *stream)
937 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
938 struct tevent_req *req;
939 struct tstream_npa_disconnect_state *state;
940 struct tevent_req *subreq;
942 req = tevent_req_create(mem_ctx, &state,
943 struct tstream_npa_disconnect_state);
944 if (req == NULL) {
945 return NULL;
948 state->stream = stream;
950 if (!npas->unix_stream) {
951 tevent_req_error(req, ENOTCONN);
952 goto post;
955 subreq = tstream_disconnect_send(state,
957 npas->unix_stream);
958 if (tevent_req_nomem(subreq, req)) {
959 goto post;
961 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
963 return req;
965 post:
966 tevent_req_post(req, ev);
967 return req;
970 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
972 struct tevent_req *req = tevent_req_callback_data(subreq,
973 struct tevent_req);
974 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
975 struct tstream_npa_disconnect_state);
976 struct tstream_context *stream = state->stream;
977 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
978 int ret;
979 int sys_errno;
981 ret = tstream_disconnect_recv(subreq, &sys_errno);
982 TALLOC_FREE(subreq);
983 if (ret == -1) {
984 tevent_req_error(req, sys_errno);
985 return;
988 TALLOC_FREE(npas->unix_stream);
990 tevent_req_done(req);
993 static int tstream_npa_disconnect_recv(struct tevent_req *req,
994 int *perrno)
996 int ret;
998 ret = tsocket_simple_int_recv(req, perrno);
1000 tevent_req_received(req);
1001 return ret;
1004 static const struct tstream_context_ops tstream_npa_ops = {
1005 .name = "npa",
1007 .pending_bytes = tstream_npa_pending_bytes,
1009 .readv_send = tstream_npa_readv_send,
1010 .readv_recv = tstream_npa_readv_recv,
1012 .writev_send = tstream_npa_writev_send,
1013 .writev_recv = tstream_npa_writev_recv,
1015 .disconnect_send = tstream_npa_disconnect_send,
1016 .disconnect_recv = tstream_npa_disconnect_recv,
1019 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1020 int fd,
1021 uint16_t file_type,
1022 struct tstream_context **_stream,
1023 const char *location)
1025 struct tstream_context *stream;
1026 struct tstream_npa *npas;
1027 int ret;
1029 switch (file_type) {
1030 case FILE_TYPE_BYTE_MODE_PIPE:
1031 break;
1032 case FILE_TYPE_MESSAGE_MODE_PIPE:
1033 break;
1034 default:
1035 errno = EINVAL;
1036 return -1;
1039 stream = tstream_context_create(mem_ctx,
1040 &tstream_npa_ops,
1041 &npas,
1042 struct tstream_npa,
1043 location);
1044 if (!stream) {
1045 return -1;
1047 ZERO_STRUCTP(npas);
1049 npas->file_type = file_type;
1051 ret = tstream_bsd_existing_socket(stream, fd,
1052 &npas->unix_stream);
1053 if (ret == -1) {
1054 int saved_errno = errno;
1055 talloc_free(stream);
1056 errno = saved_errno;
1057 return -1;
1060 *_stream = stream;
1061 return 0;
1065 struct tstream_npa_accept_state {
1066 struct tevent_context *ev;
1067 struct tstream_context *plain;
1068 uint16_t file_type;
1069 uint16_t device_state;
1070 uint64_t alloc_size;
1072 DATA_BLOB npa_blob;
1073 struct iovec out_iov;
1075 /* results */
1076 NTSTATUS accept_status;
1077 struct tsocket_address *client;
1078 char *client_name;
1079 struct tsocket_address *server;
1080 char *server_name;
1081 struct auth_session_info_transport *session_info;
1084 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1085 void *private_data,
1086 TALLOC_CTX *mem_ctx,
1087 struct iovec **_vector,
1088 size_t *_count);
1089 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1090 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1092 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1093 struct tevent_context *ev,
1094 struct tstream_context *plain,
1095 uint16_t file_type,
1096 uint16_t device_state,
1097 uint64_t allocation_size)
1099 struct tstream_npa_accept_state *state;
1100 struct tevent_req *req, *subreq;
1102 req = tevent_req_create(mem_ctx, &state,
1103 struct tstream_npa_accept_state);
1104 if (req == NULL) {
1105 return NULL;
1108 switch (file_type) {
1109 case FILE_TYPE_BYTE_MODE_PIPE:
1110 break;
1111 case FILE_TYPE_MESSAGE_MODE_PIPE:
1112 break;
1113 default:
1114 tevent_req_error(req, EINVAL);
1115 goto post;
1118 ZERO_STRUCTP(state);
1120 state->ev = ev;
1121 state->plain = plain;
1122 state->file_type = file_type;
1123 state->device_state = device_state;
1124 state->alloc_size = allocation_size;
1127 * The named pipe pdu's have the length as 8 byte (initial_read_size),
1128 * named_pipe_full_request provides the pdu length then.
1130 subreq = tstream_readv_pdu_send(state, ev, plain,
1131 tstream_npa_accept_next_vector,
1132 state);
1133 if (tevent_req_nomem(subreq, req)) {
1134 goto post;
1137 tevent_req_set_callback(subreq,
1138 tstream_npa_accept_existing_reply, req);
1140 return req;
1142 post:
1143 tevent_req_post(req, ev);
1144 return req;
1147 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1148 void *private_data,
1149 TALLOC_CTX *mem_ctx,
1150 struct iovec **_vector,
1151 size_t *_count)
1153 struct tstream_npa_accept_state *state =
1154 talloc_get_type_abort(private_data,
1155 struct tstream_npa_accept_state);
1156 struct iovec *vector;
1157 size_t count;
1158 off_t ofs = 0;
1160 if (state->npa_blob.length == 0) {
1161 state->npa_blob = data_blob_talloc(state, NULL, 4);
1162 if (!state->npa_blob.data) {
1163 return -1;
1165 } else if (state->npa_blob.length == 4) {
1166 uint32_t msg_len;
1168 ofs = 4;
1170 msg_len = RIVAL(state->npa_blob.data, 0);
1172 if (msg_len > 0x00FFFFFF) {
1173 errno = EMSGSIZE;
1174 return -1;
1177 if (msg_len == 0) {
1178 errno = EMSGSIZE;
1179 return -1;
1182 msg_len += ofs;
1184 state->npa_blob.data = talloc_realloc(state,
1185 state->npa_blob.data,
1186 uint8_t, msg_len);
1187 if (!state->npa_blob.data) {
1188 return -1;
1190 state->npa_blob.length = msg_len;
1191 } else {
1192 if (memcmp(&state->npa_blob.data[4],
1193 NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1194 DEBUG(0, ("Wrong protocol\n"));
1195 #if defined(EPROTONOSUPPORT)
1196 errno = EPROTONOSUPPORT;
1197 #elif defined(EPROTO)
1198 errno = EPROTO;
1199 #else
1200 errno = EINVAL;
1201 #endif
1202 return -1;
1204 *_vector = NULL;
1205 *_count = 0;
1206 return 0;
1209 /* we need to get a message header */
1210 vector = talloc_array(mem_ctx, struct iovec, 1);
1211 if (!vector) {
1212 return -1;
1214 vector[0].iov_base = (char *) (state->npa_blob.data + ofs);
1215 vector[0].iov_len = state->npa_blob.length - ofs;
1216 count = 1;
1218 *_vector = vector;
1219 *_count = count;
1220 return 0;
1223 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1225 struct tevent_req *req =
1226 tevent_req_callback_data(subreq, struct tevent_req);
1227 struct tstream_npa_accept_state *state =
1228 tevent_req_data(req, struct tstream_npa_accept_state);
1229 struct named_pipe_auth_req *pipe_request;
1230 struct named_pipe_auth_rep pipe_reply;
1231 struct named_pipe_auth_req_info4 i4;
1232 enum ndr_err_code ndr_err;
1233 DATA_BLOB out;
1234 int sys_errno;
1235 int ret;
1237 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1238 TALLOC_FREE(subreq);
1239 if (ret == -1) {
1240 tevent_req_error(req, sys_errno);
1241 return;
1244 DEBUG(10, ("Received packet of length %lu\n",
1245 (long)state->npa_blob.length));
1246 dump_data(11, state->npa_blob.data, state->npa_blob.length);
1248 ZERO_STRUCT(pipe_reply);
1249 pipe_reply.level = 0;
1250 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1252 * TODO: check it's a root (uid == 0) pipe
1255 pipe_request = talloc(state, struct named_pipe_auth_req);
1256 if (!pipe_request) {
1257 DEBUG(0, ("Out of memory!\n"));
1258 goto reply;
1261 /* parse the passed credentials */
1262 ndr_err = ndr_pull_struct_blob_all(
1263 &state->npa_blob, pipe_request, pipe_request,
1264 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1265 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1266 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1267 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1268 nt_errstr(pipe_reply.status)));
1269 goto reply;
1272 if (DEBUGLVL(10)) {
1273 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1276 ZERO_STRUCT(i4);
1278 if (pipe_request->level != 4) {
1279 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1280 pipe_reply.level = 0;
1281 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1282 goto reply;
1285 pipe_reply.level = 4;
1286 pipe_reply.status = NT_STATUS_OK;
1287 pipe_reply.info.info4.file_type = state->file_type;
1288 pipe_reply.info.info4.device_state = state->device_state;
1289 pipe_reply.info.info4.allocation_size = state->alloc_size;
1291 i4 = pipe_request->info.info4;
1292 if (i4.server_addr == NULL) {
1293 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1294 DEBUG(2, ("Missing server address\n"));
1295 goto reply;
1297 if (i4.client_addr == NULL) {
1298 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1299 DEBUG(2, ("Missing client address\n"));
1300 goto reply;
1303 state->server_name = discard_const_p(char,
1304 talloc_move(state, &i4.server_name));
1305 ret = tsocket_address_inet_from_strings(state, "ip",
1306 i4.server_addr,
1307 i4.server_port,
1308 &state->server);
1309 if (ret != 0) {
1310 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1311 i4.server_addr, i4.server_port,
1312 strerror(errno)));
1313 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1314 goto reply;
1317 state->client_name = discard_const_p(char,
1318 talloc_move(state, &i4.client_name));
1319 ret = tsocket_address_inet_from_strings(state, "ip",
1320 i4.client_addr,
1321 i4.client_port,
1322 &state->client);
1323 if (ret != 0) {
1324 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1325 i4.client_addr, i4.client_port,
1326 strerror(errno)));
1327 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1328 goto reply;
1331 state->session_info = talloc_move(state, &i4.session_info);
1332 reply:
1333 /* create the output */
1334 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1335 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337 DEBUG(2, ("Error encoding structure: %s",
1338 ndr_map_error2string(ndr_err)));
1339 tevent_req_error(req, EIO);
1340 return;
1343 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1344 dump_data(11, out.data, out.length);
1346 if (DEBUGLVL(10)) {
1347 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1350 state->accept_status = pipe_reply.status;
1352 state->out_iov.iov_base = (char *) out.data;
1353 state->out_iov.iov_len = out.length;
1355 subreq = tstream_writev_send(state, state->ev,
1356 state->plain,
1357 &state->out_iov, 1);
1358 if (tevent_req_nomem(subreq, req)) {
1359 DEBUG(0, ("no memory for tstream_writev_send"));
1360 return;
1363 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1366 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1368 struct tevent_req *req =
1369 tevent_req_callback_data(subreq, struct tevent_req);
1370 int sys_errno;
1371 int ret;
1373 ret = tstream_writev_recv(subreq, &sys_errno);
1374 TALLOC_FREE(subreq);
1375 if (ret == -1) {
1376 tevent_req_error(req, sys_errno);
1377 return;
1380 tevent_req_done(req);
1383 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1384 int *perrno,
1385 TALLOC_CTX *mem_ctx,
1386 struct tstream_context **stream,
1387 struct tsocket_address **client,
1388 char **_client_name,
1389 struct tsocket_address **server,
1390 char **server_name,
1391 struct auth_session_info_transport **session_info,
1392 const char *location)
1394 struct tstream_npa_accept_state *state =
1395 tevent_req_data(req, struct tstream_npa_accept_state);
1396 struct tstream_npa *npas;
1397 int ret;
1399 ret = tsocket_simple_int_recv(req, perrno);
1400 if (ret != 0) {
1401 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1402 strerror(*perrno)));
1403 tevent_req_received(req);
1404 return -1;
1407 if (!NT_STATUS_IS_OK(state->accept_status)) {
1408 #if defined(EPROTONOSUPPORT)
1409 *perrno = EPROTONOSUPPORT;
1410 #elif defined(EPROTO)
1411 *perrno = EPROTO;
1412 #else
1413 *perrno = EINVAL;
1414 #endif
1415 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1416 nt_errstr(state->accept_status),
1417 strerror(*perrno)));
1418 tevent_req_received(req);
1419 return -1;
1422 *stream = tstream_context_create(mem_ctx,
1423 &tstream_npa_ops,
1424 &npas,
1425 struct tstream_npa,
1426 location);
1427 if (!*stream) {
1428 *perrno = ENOMEM;
1429 tevent_req_received(req);
1430 return -1;
1432 ZERO_STRUCTP(npas);
1433 npas->unix_stream = state->plain;
1434 npas->file_type = state->file_type;
1436 *client = talloc_move(mem_ctx, &state->client);
1437 *_client_name = talloc_move(mem_ctx, &state->client_name);
1438 *server = talloc_move(mem_ctx, &state->server);
1439 *server_name = talloc_move(mem_ctx, &state->server_name);
1440 *session_info = talloc_move(mem_ctx, &state->session_info);
1442 tevent_req_received(req);
1443 return 0;