s3:selftest: also run test_smbclient_s3.sh with PROTO=SMB3
[Samba.git] / libcli / named_pipe_auth / npa_tstream.c
blobd333ce6ee229ed59747cac3b0d7d66a41ec3de60
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 *remote_client_addr,
64 const char *remote_client_name_in,
65 const struct tsocket_address *local_server_addr,
66 const char *local_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 (!local_server_addr) {
117 tevent_req_error(req, EINVAL);
118 goto post;
121 state->auth_req.level = 4;
122 info4 = &state->auth_req.info.info4;
124 info4->remote_client_name = remote_client_name_in;
125 info4->remote_client_addr = tsocket_address_inet_addr_string(remote_client_addr,
126 state);
127 if (!info4->remote_client_addr) {
128 /* errno might be EINVAL */
129 tevent_req_error(req, errno);
130 goto post;
132 info4->remote_client_port = tsocket_address_inet_port(remote_client_addr);
133 if (!info4->remote_client_name) {
134 info4->remote_client_name = info4->remote_client_addr;
137 info4->local_server_addr = tsocket_address_inet_addr_string(local_server_addr,
138 state);
139 if (!info4->local_server_addr) {
140 /* errno might be EINVAL */
141 tevent_req_error(req, errno);
142 goto post;
144 info4->local_server_port = tsocket_address_inet_port(local_server_addr);
145 if (!info4->local_server_name) {
146 info4->local_server_name = info4->local_server_addr;
149 info4->session_info = discard_const_p(struct auth_session_info_transport, session_info);
151 if (DEBUGLVL(10)) {
152 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
155 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
156 state, &state->auth_req,
157 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
158 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
159 tevent_req_error(req, EINVAL);
160 goto post;
163 state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
164 state->auth_req_iov.iov_len = state->auth_req_blob.length;
166 subreq = tstream_unix_connect_send(state,
167 state->caller.ev,
168 state->unix_laddr,
169 state->unix_raddr);
170 if (tevent_req_nomem(subreq, req)) {
171 goto post;
173 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
175 return req;
177 post:
178 tevent_req_post(req, ev);
179 return req;
182 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
184 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
186 struct tevent_req *req =
187 tevent_req_callback_data(subreq,
188 struct tevent_req);
189 struct tstream_npa_connect_state *state =
190 tevent_req_data(req,
191 struct tstream_npa_connect_state);
192 int ret;
193 int sys_errno;
195 ret = tstream_unix_connect_recv(subreq, &sys_errno,
196 state, &state->unix_stream);
197 TALLOC_FREE(subreq);
198 if (ret == -1) {
199 tevent_req_error(req, sys_errno);
200 return;
203 subreq = tstream_writev_send(state,
204 state->caller.ev,
205 state->unix_stream,
206 &state->auth_req_iov, 1);
207 if (tevent_req_nomem(subreq, req)) {
208 return;
210 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
213 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
214 void *private_data,
215 TALLOC_CTX *mem_ctx,
216 struct iovec **_vector,
217 size_t *_count);
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 state->auth_rep_blob = data_blob_const(NULL, 0);
240 subreq = tstream_readv_pdu_send(state, state->caller.ev,
241 state->unix_stream,
242 tstream_npa_connect_next_vector,
243 state);
244 if (tevent_req_nomem(subreq, req)) {
245 return;
247 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
250 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
251 void *private_data,
252 TALLOC_CTX *mem_ctx,
253 struct iovec **_vector,
254 size_t *_count)
256 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
257 struct tstream_npa_connect_state);
258 struct iovec *vector;
259 size_t count;
260 off_t ofs = 0;
262 if (state->auth_rep_blob.length == 0) {
263 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
264 if (!state->auth_rep_blob.data) {
265 return -1;
267 } else if (state->auth_rep_blob.length == 4) {
268 uint32_t msg_len;
270 ofs = 4;
272 msg_len = RIVAL(state->auth_rep_blob.data, 0);
274 if (msg_len > 0x00FFFFFF) {
275 errno = EMSGSIZE;
276 return -1;
279 if (msg_len == 0) {
280 errno = EMSGSIZE;
281 return -1;
284 msg_len += ofs;
286 state->auth_rep_blob.data = talloc_realloc(state,
287 state->auth_rep_blob.data,
288 uint8_t, msg_len);
289 if (!state->auth_rep_blob.data) {
290 return -1;
292 state->auth_rep_blob.length = msg_len;
293 } else {
294 *_vector = NULL;
295 *_count = 0;
296 return 0;
299 /* we need to get a message header */
300 vector = talloc_array(mem_ctx, struct iovec, 1);
301 if (!vector) {
302 return -1;
304 vector[0].iov_base = (char *) (state->auth_rep_blob.data + ofs);
305 vector[0].iov_len = state->auth_rep_blob.length - ofs;
306 count = 1;
308 *_vector = vector;
309 *_count = count;
310 return 0;
313 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
315 struct tevent_req *req =
316 tevent_req_callback_data(subreq,
317 struct tevent_req);
318 struct tstream_npa_connect_state *state =
319 tevent_req_data(req,
320 struct tstream_npa_connect_state);
321 int ret;
322 int sys_errno;
323 enum ndr_err_code ndr_err;
325 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
326 TALLOC_FREE(subreq);
327 if (ret == -1) {
328 tevent_req_error(req, sys_errno);
329 return;
332 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
333 (uint32_t)state->auth_rep_blob.length));
334 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
336 ndr_err = ndr_pull_struct_blob(
337 &state->auth_rep_blob, state,
338 &state->auth_rep,
339 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
341 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
342 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
343 ndr_map_error2string(ndr_err)));
344 tevent_req_error(req, EIO);
345 return;
348 if (DEBUGLVL(10)) {
349 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
352 if (state->auth_rep.length < 16) {
353 DEBUG(0, ("req invalid length: %u < 16\n",
354 state->auth_rep.length));
355 tevent_req_error(req, EIO);
356 return;
359 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
360 DEBUG(0, ("req invalid magic: %s != %s\n",
361 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
362 tevent_req_error(req, EIO);
363 return;
366 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
367 DEBUG(0, ("req failed: %s\n",
368 nt_errstr(state->auth_rep.status)));
369 tevent_req_error(req, EACCES);
370 return;
373 if (state->auth_rep.level != state->auth_req.level) {
374 DEBUG(0, ("req invalid level: %u != %u\n",
375 state->auth_rep.level, state->auth_req.level));
376 tevent_req_error(req, EIO);
377 return;
380 tevent_req_done(req);
383 int _tstream_npa_connect_recv(struct tevent_req *req,
384 int *perrno,
385 TALLOC_CTX *mem_ctx,
386 struct tstream_context **_stream,
387 uint16_t *_file_type,
388 uint16_t *_device_state,
389 uint64_t *_allocation_size,
390 const char *location)
392 struct tstream_npa_connect_state *state =
393 tevent_req_data(req,
394 struct tstream_npa_connect_state);
395 struct tstream_context *stream;
396 struct tstream_npa *npas;
397 uint16_t device_state = 0;
398 uint64_t allocation_size = 0;
400 if (tevent_req_is_unix_error(req, perrno)) {
401 tevent_req_received(req);
402 return -1;
405 stream = tstream_context_create(mem_ctx,
406 &tstream_npa_ops,
407 &npas,
408 struct tstream_npa,
409 location);
410 if (!stream) {
411 *perrno = ENOMEM;
412 tevent_req_received(req);
413 return -1;
415 ZERO_STRUCTP(npas);
417 npas->unix_stream = talloc_move(stream, &state->unix_stream);
418 switch (state->auth_rep.level) {
419 case 4:
420 npas->file_type = state->auth_rep.info.info4.file_type;
421 device_state = state->auth_rep.info.info4.device_state;
422 allocation_size = state->auth_rep.info.info4.allocation_size;
423 break;
426 *_stream = stream;
427 *_file_type = npas->file_type;
428 *_device_state = device_state;
429 *_allocation_size = allocation_size;
430 tevent_req_received(req);
431 return 0;
434 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
436 struct tstream_npa *npas = tstream_context_data(stream,
437 struct tstream_npa);
438 ssize_t ret;
440 if (!npas->unix_stream) {
441 errno = ENOTCONN;
442 return -1;
445 switch (npas->file_type) {
446 case FILE_TYPE_BYTE_MODE_PIPE:
447 ret = tstream_pending_bytes(npas->unix_stream);
448 break;
450 case FILE_TYPE_MESSAGE_MODE_PIPE:
451 ret = npas->pending.iov_len;
452 break;
454 default:
455 ret = -1;
458 return ret;
461 struct tstream_npa_readv_state {
462 struct tstream_context *stream;
464 struct iovec *vector;
465 size_t count;
467 /* the header for message mode */
468 uint8_t hdr[2];
469 bool wait_for_hdr;
471 int ret;
474 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
475 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
476 void *private_data,
477 TALLOC_CTX *mem_ctx,
478 struct iovec **_vector,
479 size_t *_count);
480 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
482 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
483 struct tevent_context *ev,
484 struct tstream_context *stream,
485 struct iovec *vector,
486 size_t count)
488 struct tevent_req *req;
489 struct tstream_npa_readv_state *state;
490 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
491 struct tevent_req *subreq;
492 off_t ofs;
493 size_t left;
494 uint8_t *pbase;
496 req = tevent_req_create(mem_ctx, &state,
497 struct tstream_npa_readv_state);
498 if (!req) {
499 return NULL;
502 state->stream = stream;
503 state->ret = 0;
505 if (!npas->unix_stream) {
506 tevent_req_error(req, ENOTCONN);
507 goto post;
510 switch (npas->file_type) {
511 case FILE_TYPE_BYTE_MODE_PIPE:
512 state->vector = vector;
513 state->count = count;
515 subreq = tstream_readv_send(state,
517 npas->unix_stream,
518 state->vector,
519 state->count);
520 if (tevent_req_nomem(subreq,req)) {
521 goto post;
523 tevent_req_set_callback(subreq,
524 tstream_npa_readv_byte_mode_handler,
525 req);
527 return req;
529 case FILE_TYPE_MESSAGE_MODE_PIPE:
531 * we make a copy of the vector and prepend a header
532 * with the length
534 state->vector = talloc_array(state, struct iovec, count);
535 if (tevent_req_nomem(state->vector, req)) {
536 goto post;
538 memcpy(state->vector, vector, sizeof(struct iovec)*count);
539 state->count = count;
542 * copy the pending buffer first
544 ofs = 0;
545 left = npas->pending.iov_len;
546 pbase = (uint8_t *)npas->pending.iov_base;
548 while (left > 0 && state->count > 0) {
549 uint8_t *base;
550 base = (uint8_t *)state->vector[0].iov_base;
551 if (left < state->vector[0].iov_len) {
552 memcpy(base, pbase + ofs, left);
554 base += left;
555 state->vector[0].iov_base = (char *) base;
556 state->vector[0].iov_len -= left;
558 ofs += left;
559 left = 0;
560 TALLOC_FREE(pbase);
561 ZERO_STRUCT(npas->pending);
562 break;
564 memcpy(base, pbase + ofs, state->vector[0].iov_len);
566 ofs += state->vector[0].iov_len;
567 left -= state->vector[0].iov_len;
568 state->vector += 1;
569 state->count -= 1;
571 if (left == 0) {
572 TALLOC_FREE(pbase);
573 ZERO_STRUCT(npas->pending);
574 break;
578 if (left > 0) {
579 memmove(pbase, pbase + ofs, left);
580 npas->pending.iov_base = (char *) pbase;
581 npas->pending.iov_len = left;
583 * this cannot fail and even if it
584 * fails we can handle it
586 pbase = talloc_realloc(npas, pbase, uint8_t, left);
587 if (pbase) {
588 npas->pending.iov_base = (char *) pbase;
590 pbase = NULL;
593 state->ret += ofs;
595 if (state->count == 0) {
596 tevent_req_done(req);
597 goto post;
600 ZERO_STRUCT(state->hdr);
601 state->wait_for_hdr = false;
603 subreq = tstream_readv_pdu_send(state,
605 npas->unix_stream,
606 tstream_npa_readv_next_vector,
607 state);
608 if (tevent_req_nomem(subreq, req)) {
609 goto post;
611 tevent_req_set_callback(subreq,
612 tstream_npa_readv_msg_mode_handler,
613 req);
615 return req;
618 /* this can't happen */
619 tevent_req_error(req, EINVAL);
620 goto post;
622 post:
623 tevent_req_post(req, ev);
624 return req;
627 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
629 struct tevent_req *req = tevent_req_callback_data(subreq,
630 struct tevent_req);
631 struct tstream_npa_readv_state *state = tevent_req_data(req,
632 struct tstream_npa_readv_state);
633 int ret;
634 int sys_errno;
636 ret = tstream_readv_recv(subreq, &sys_errno);
637 TALLOC_FREE(subreq);
638 if (ret == -1) {
639 tevent_req_error(req, sys_errno);
640 return;
643 state->ret = ret;
645 tevent_req_done(req);
648 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
649 void *private_data,
650 TALLOC_CTX *mem_ctx,
651 struct iovec **_vector,
652 size_t *_count)
654 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
655 struct tstream_npa_readv_state);
656 struct tstream_npa *npas = tstream_context_data(state->stream,
657 struct tstream_npa);
658 struct iovec *vector;
659 size_t count;
660 uint16_t msg_len;
661 size_t left;
663 if (state->count == 0) {
664 *_vector = NULL;
665 *_count = 0;
666 return 0;
669 if (!state->wait_for_hdr) {
670 /* we need to get a message header */
671 vector = talloc_array(mem_ctx, struct iovec, 1);
672 if (!vector) {
673 return -1;
675 ZERO_STRUCT(state->hdr);
676 vector[0].iov_base = (char *) state->hdr;
677 vector[0].iov_len = sizeof(state->hdr);
679 count = 1;
681 state->wait_for_hdr = true;
683 *_vector = vector;
684 *_count = count;
685 return 0;
688 /* and now fill the callers buffers and maybe the pending buffer */
689 state->wait_for_hdr = false;
691 msg_len = SVAL(state->hdr, 0);
693 if (msg_len == 0) {
694 errno = EIO;
695 return -1;
698 state->wait_for_hdr = false;
700 /* +1 because we may need to fill the pending buffer */
701 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
702 if (!vector) {
703 return -1;
706 count = 0;
707 left = msg_len;
708 while (left > 0 && state->count > 0) {
709 if (left < state->vector[0].iov_len) {
710 uint8_t *base;
711 base = (uint8_t *)state->vector[0].iov_base;
712 vector[count].iov_base = (char *) base;
713 vector[count].iov_len = left;
714 count++;
715 base += left;
716 state->vector[0].iov_base = (char *) base;
717 state->vector[0].iov_len -= left;
718 break;
720 vector[count] = state->vector[0];
721 count++;
722 left -= state->vector[0].iov_len;
723 state->vector += 1;
724 state->count -= 1;
727 if (left > 0) {
729 * if the message is longer than the buffers the caller
730 * requested, we need to consume the rest of the message
731 * into the pending buffer, where the next readv can
732 * be served from.
734 npas->pending.iov_base = talloc_array(npas, char, left);
735 if (!npas->pending.iov_base) {
736 return -1;
738 npas->pending.iov_len = left;
740 vector[count] = npas->pending;
741 count++;
744 state->ret += (msg_len - left);
746 *_vector = vector;
747 *_count = count;
748 return 0;
751 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
753 struct tevent_req *req = tevent_req_callback_data(subreq,
754 struct tevent_req);
755 int ret;
756 int sys_errno;
758 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
759 TALLOC_FREE(subreq);
760 if (ret == -1) {
761 tevent_req_error(req, sys_errno);
762 return;
766 * we do not set state->ret here as ret includes the headr size.
767 * we set it in tstream_npa_readv_pdu_next_vector()
770 tevent_req_done(req);
773 static int tstream_npa_readv_recv(struct tevent_req *req,
774 int *perrno)
776 struct tstream_npa_readv_state *state = tevent_req_data(req,
777 struct tstream_npa_readv_state);
778 int ret;
780 ret = tsocket_simple_int_recv(req, perrno);
781 if (ret == 0) {
782 ret = state->ret;
785 tevent_req_received(req);
786 return ret;
789 struct tstream_npa_writev_state {
790 const struct iovec *vector;
791 size_t count;
793 /* the header for message mode */
794 bool hdr_used;
795 uint8_t hdr[2];
797 int ret;
800 static void tstream_npa_writev_handler(struct tevent_req *subreq);
802 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
803 struct tevent_context *ev,
804 struct tstream_context *stream,
805 const struct iovec *vector,
806 size_t count)
808 struct tevent_req *req;
809 struct tstream_npa_writev_state *state;
810 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
811 struct tevent_req *subreq;
812 size_t msg_len;
813 size_t i;
814 struct iovec *new_vector;
816 req = tevent_req_create(mem_ctx, &state,
817 struct tstream_npa_writev_state);
818 if (!req) {
819 return NULL;
822 state->ret = 0;
824 if (!npas->unix_stream) {
825 tevent_req_error(req, ENOTCONN);
826 goto post;
829 switch (npas->file_type) {
830 case FILE_TYPE_BYTE_MODE_PIPE:
831 state->hdr_used = false;
832 state->vector = vector;
833 state->count = count;
834 break;
836 case FILE_TYPE_MESSAGE_MODE_PIPE:
838 * we make a copy of the vector and prepend a header
839 * with the length
841 new_vector = talloc_array(state, struct iovec, count + 1);
842 if (tevent_req_nomem(new_vector, req)) {
843 goto post;
845 new_vector[0].iov_base = (char *) state->hdr;
846 new_vector[0].iov_len = sizeof(state->hdr);
847 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
849 state->hdr_used = true;
850 state->vector = new_vector;
851 state->count = count + 1;
853 msg_len = 0;
854 for (i=0; i < count; i++) {
855 msg_len += vector[i].iov_len;
858 if (msg_len > UINT16_MAX) {
859 tevent_req_error(req, EMSGSIZE);
860 goto post;
863 SSVAL(state->hdr, 0, msg_len);
864 break;
867 subreq = tstream_writev_send(state,
869 npas->unix_stream,
870 state->vector,
871 state->count);
872 if (tevent_req_nomem(subreq, req)) {
873 goto post;
875 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
877 return req;
879 post:
880 tevent_req_post(req, ev);
881 return req;
884 static void tstream_npa_writev_handler(struct tevent_req *subreq)
886 struct tevent_req *req = tevent_req_callback_data(subreq,
887 struct tevent_req);
888 struct tstream_npa_writev_state *state = tevent_req_data(req,
889 struct tstream_npa_writev_state);
890 int ret;
891 int sys_errno;
893 ret = tstream_writev_recv(subreq, &sys_errno);
894 TALLOC_FREE(subreq);
895 if (ret == -1) {
896 tevent_req_error(req, sys_errno);
897 return;
901 * in message mode we need to hide the length
902 * of the hdr from the caller
904 if (state->hdr_used) {
905 ret -= sizeof(state->hdr);
908 state->ret = ret;
910 tevent_req_done(req);
913 static int tstream_npa_writev_recv(struct tevent_req *req,
914 int *perrno)
916 struct tstream_npa_writev_state *state = tevent_req_data(req,
917 struct tstream_npa_writev_state);
918 int ret;
920 ret = tsocket_simple_int_recv(req, perrno);
921 if (ret == 0) {
922 ret = state->ret;
925 tevent_req_received(req);
926 return ret;
929 struct tstream_npa_disconnect_state {
930 struct tstream_context *stream;
933 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
935 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
936 struct tevent_context *ev,
937 struct tstream_context *stream)
939 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
940 struct tevent_req *req;
941 struct tstream_npa_disconnect_state *state;
942 struct tevent_req *subreq;
944 req = tevent_req_create(mem_ctx, &state,
945 struct tstream_npa_disconnect_state);
946 if (req == NULL) {
947 return NULL;
950 state->stream = stream;
952 if (!npas->unix_stream) {
953 tevent_req_error(req, ENOTCONN);
954 goto post;
957 subreq = tstream_disconnect_send(state,
959 npas->unix_stream);
960 if (tevent_req_nomem(subreq, req)) {
961 goto post;
963 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
965 return req;
967 post:
968 tevent_req_post(req, ev);
969 return req;
972 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
974 struct tevent_req *req = tevent_req_callback_data(subreq,
975 struct tevent_req);
976 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
977 struct tstream_npa_disconnect_state);
978 struct tstream_context *stream = state->stream;
979 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
980 int ret;
981 int sys_errno;
983 ret = tstream_disconnect_recv(subreq, &sys_errno);
984 TALLOC_FREE(subreq);
985 if (ret == -1) {
986 tevent_req_error(req, sys_errno);
987 return;
990 TALLOC_FREE(npas->unix_stream);
992 tevent_req_done(req);
995 static int tstream_npa_disconnect_recv(struct tevent_req *req,
996 int *perrno)
998 int ret;
1000 ret = tsocket_simple_int_recv(req, perrno);
1002 tevent_req_received(req);
1003 return ret;
1006 static const struct tstream_context_ops tstream_npa_ops = {
1007 .name = "npa",
1009 .pending_bytes = tstream_npa_pending_bytes,
1011 .readv_send = tstream_npa_readv_send,
1012 .readv_recv = tstream_npa_readv_recv,
1014 .writev_send = tstream_npa_writev_send,
1015 .writev_recv = tstream_npa_writev_recv,
1017 .disconnect_send = tstream_npa_disconnect_send,
1018 .disconnect_recv = tstream_npa_disconnect_recv,
1021 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1022 int fd,
1023 uint16_t file_type,
1024 struct tstream_context **_stream,
1025 const char *location)
1027 struct tstream_context *stream;
1028 struct tstream_npa *npas;
1029 int ret;
1031 switch (file_type) {
1032 case FILE_TYPE_BYTE_MODE_PIPE:
1033 break;
1034 case FILE_TYPE_MESSAGE_MODE_PIPE:
1035 break;
1036 default:
1037 errno = EINVAL;
1038 return -1;
1041 stream = tstream_context_create(mem_ctx,
1042 &tstream_npa_ops,
1043 &npas,
1044 struct tstream_npa,
1045 location);
1046 if (!stream) {
1047 return -1;
1049 ZERO_STRUCTP(npas);
1051 npas->file_type = file_type;
1053 ret = tstream_bsd_existing_socket(stream, fd,
1054 &npas->unix_stream);
1055 if (ret == -1) {
1056 int saved_errno = errno;
1057 talloc_free(stream);
1058 errno = saved_errno;
1059 return -1;
1062 *_stream = stream;
1063 return 0;
1067 struct tstream_npa_accept_state {
1068 struct tevent_context *ev;
1069 struct tstream_context *plain;
1070 uint16_t file_type;
1071 uint16_t device_state;
1072 uint64_t alloc_size;
1074 DATA_BLOB npa_blob;
1075 struct iovec out_iov;
1077 /* results */
1078 NTSTATUS accept_status;
1079 struct tsocket_address *remote_client_addr;
1080 char *remote_client_name;
1081 struct tsocket_address *local_server_addr;
1082 char *local_server_name;
1083 struct auth_session_info_transport *session_info;
1086 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1087 void *private_data,
1088 TALLOC_CTX *mem_ctx,
1089 struct iovec **_vector,
1090 size_t *_count);
1091 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1092 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1094 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1095 struct tevent_context *ev,
1096 struct tstream_context *plain,
1097 uint16_t file_type,
1098 uint16_t device_state,
1099 uint64_t allocation_size)
1101 struct tstream_npa_accept_state *state;
1102 struct tevent_req *req, *subreq;
1104 req = tevent_req_create(mem_ctx, &state,
1105 struct tstream_npa_accept_state);
1106 if (req == NULL) {
1107 return NULL;
1110 switch (file_type) {
1111 case FILE_TYPE_BYTE_MODE_PIPE:
1112 break;
1113 case FILE_TYPE_MESSAGE_MODE_PIPE:
1114 break;
1115 default:
1116 tevent_req_error(req, EINVAL);
1117 goto post;
1120 ZERO_STRUCTP(state);
1122 state->ev = ev;
1123 state->plain = plain;
1124 state->file_type = file_type;
1125 state->device_state = device_state;
1126 state->alloc_size = allocation_size;
1129 * The named pipe pdu's have the length as 8 byte (initial_read_size),
1130 * named_pipe_full_request provides the pdu length then.
1132 subreq = tstream_readv_pdu_send(state, ev, plain,
1133 tstream_npa_accept_next_vector,
1134 state);
1135 if (tevent_req_nomem(subreq, req)) {
1136 goto post;
1139 tevent_req_set_callback(subreq,
1140 tstream_npa_accept_existing_reply, req);
1142 return req;
1144 post:
1145 tevent_req_post(req, ev);
1146 return req;
1149 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1150 void *private_data,
1151 TALLOC_CTX *mem_ctx,
1152 struct iovec **_vector,
1153 size_t *_count)
1155 struct tstream_npa_accept_state *state =
1156 talloc_get_type_abort(private_data,
1157 struct tstream_npa_accept_state);
1158 struct iovec *vector;
1159 size_t count;
1160 off_t ofs = 0;
1162 if (state->npa_blob.length == 0) {
1163 state->npa_blob = data_blob_talloc(state, NULL, 4);
1164 if (!state->npa_blob.data) {
1165 return -1;
1167 } else if (state->npa_blob.length == 4) {
1168 uint32_t msg_len;
1170 ofs = 4;
1172 msg_len = RIVAL(state->npa_blob.data, 0);
1174 if (msg_len > 0x00FFFFFF) {
1175 errno = EMSGSIZE;
1176 return -1;
1179 if (msg_len == 0) {
1180 errno = EMSGSIZE;
1181 return -1;
1184 msg_len += ofs;
1186 state->npa_blob.data = talloc_realloc(state,
1187 state->npa_blob.data,
1188 uint8_t, msg_len);
1189 if (!state->npa_blob.data) {
1190 return -1;
1192 state->npa_blob.length = msg_len;
1193 } else {
1194 if (memcmp(&state->npa_blob.data[4],
1195 NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1196 DEBUG(0, ("Wrong protocol\n"));
1197 #if defined(EPROTONOSUPPORT)
1198 errno = EPROTONOSUPPORT;
1199 #elif defined(EPROTO)
1200 errno = EPROTO;
1201 #else
1202 errno = EINVAL;
1203 #endif
1204 return -1;
1206 *_vector = NULL;
1207 *_count = 0;
1208 return 0;
1211 /* we need to get a message header */
1212 vector = talloc_array(mem_ctx, struct iovec, 1);
1213 if (!vector) {
1214 return -1;
1216 vector[0].iov_base = (char *) (state->npa_blob.data + ofs);
1217 vector[0].iov_len = state->npa_blob.length - ofs;
1218 count = 1;
1220 *_vector = vector;
1221 *_count = count;
1222 return 0;
1225 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1227 struct tevent_req *req =
1228 tevent_req_callback_data(subreq, struct tevent_req);
1229 struct tstream_npa_accept_state *state =
1230 tevent_req_data(req, struct tstream_npa_accept_state);
1231 struct named_pipe_auth_req *pipe_request;
1232 struct named_pipe_auth_rep pipe_reply;
1233 struct named_pipe_auth_req_info4 i4;
1234 enum ndr_err_code ndr_err;
1235 DATA_BLOB out;
1236 int sys_errno;
1237 int ret;
1239 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1240 TALLOC_FREE(subreq);
1241 if (ret == -1) {
1242 tevent_req_error(req, sys_errno);
1243 return;
1246 DEBUG(10, ("Received packet of length %lu\n",
1247 (long)state->npa_blob.length));
1248 dump_data(11, state->npa_blob.data, state->npa_blob.length);
1250 ZERO_STRUCT(pipe_reply);
1251 pipe_reply.level = 0;
1252 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1254 * TODO: check it's a root (uid == 0) pipe
1257 pipe_request = talloc(state, struct named_pipe_auth_req);
1258 if (!pipe_request) {
1259 DEBUG(0, ("Out of memory!\n"));
1260 goto reply;
1263 /* parse the passed credentials */
1264 ndr_err = ndr_pull_struct_blob_all(
1265 &state->npa_blob, pipe_request, pipe_request,
1266 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1268 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1269 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1270 nt_errstr(pipe_reply.status)));
1271 goto reply;
1274 if (DEBUGLVL(10)) {
1275 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1278 ZERO_STRUCT(i4);
1280 if (pipe_request->level != 4) {
1281 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1282 pipe_reply.level = 0;
1283 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1284 goto reply;
1287 pipe_reply.level = 4;
1288 pipe_reply.status = NT_STATUS_OK;
1289 pipe_reply.info.info4.file_type = state->file_type;
1290 pipe_reply.info.info4.device_state = state->device_state;
1291 pipe_reply.info.info4.allocation_size = state->alloc_size;
1293 i4 = pipe_request->info.info4;
1294 if (i4.local_server_addr == NULL) {
1295 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1296 DEBUG(2, ("Missing local server address\n"));
1297 goto reply;
1299 if (i4.remote_client_addr == NULL) {
1300 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1301 DEBUG(2, ("Missing remote client address\n"));
1302 goto reply;
1305 state->local_server_name = discard_const_p(char,
1306 talloc_move(state,
1307 &i4.local_server_name));
1308 ret = tsocket_address_inet_from_strings(state, "ip",
1309 i4.local_server_addr,
1310 i4.local_server_port,
1311 &state->local_server_addr);
1312 if (ret != 0) {
1313 DEBUG(2, ("Invalid local server address[%s:%u] - %s\n",
1314 i4.local_server_addr, i4.local_server_port,
1315 strerror(errno)));
1316 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1317 goto reply;
1320 state->remote_client_name = discard_const_p(char,
1321 talloc_move(state,
1322 &i4.remote_client_name));
1323 ret = tsocket_address_inet_from_strings(state, "ip",
1324 i4.remote_client_addr,
1325 i4.remote_client_port,
1326 &state->remote_client_addr);
1327 if (ret != 0) {
1328 DEBUG(2, ("Invalid remote client address[%s:%u] - %s\n",
1329 i4.remote_client_addr, i4.remote_client_port,
1330 strerror(errno)));
1331 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1332 goto reply;
1335 state->session_info = talloc_move(state, &i4.session_info);
1336 reply:
1337 /* create the output */
1338 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1339 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1340 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1341 DEBUG(2, ("Error encoding structure: %s",
1342 ndr_map_error2string(ndr_err)));
1343 tevent_req_error(req, EIO);
1344 return;
1347 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1348 dump_data(11, out.data, out.length);
1350 if (DEBUGLVL(10)) {
1351 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1354 state->accept_status = pipe_reply.status;
1356 state->out_iov.iov_base = (char *) out.data;
1357 state->out_iov.iov_len = out.length;
1359 subreq = tstream_writev_send(state, state->ev,
1360 state->plain,
1361 &state->out_iov, 1);
1362 if (tevent_req_nomem(subreq, req)) {
1363 DEBUG(0, ("no memory for tstream_writev_send"));
1364 return;
1367 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1370 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1372 struct tevent_req *req =
1373 tevent_req_callback_data(subreq, struct tevent_req);
1374 int sys_errno;
1375 int ret;
1377 ret = tstream_writev_recv(subreq, &sys_errno);
1378 TALLOC_FREE(subreq);
1379 if (ret == -1) {
1380 tevent_req_error(req, sys_errno);
1381 return;
1384 tevent_req_done(req);
1387 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1388 int *perrno,
1389 TALLOC_CTX *mem_ctx,
1390 struct tstream_context **stream,
1391 struct tsocket_address **remote_client_addr,
1392 char **_remote_client_name,
1393 struct tsocket_address **local_server_addr,
1394 char **local_server_name,
1395 struct auth_session_info_transport **session_info,
1396 const char *location)
1398 struct tstream_npa_accept_state *state =
1399 tevent_req_data(req, struct tstream_npa_accept_state);
1400 struct tstream_npa *npas;
1401 int ret;
1403 ret = tsocket_simple_int_recv(req, perrno);
1404 if (ret != 0) {
1405 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1406 strerror(*perrno)));
1407 tevent_req_received(req);
1408 return -1;
1411 if (!NT_STATUS_IS_OK(state->accept_status)) {
1412 #if defined(EPROTONOSUPPORT)
1413 *perrno = EPROTONOSUPPORT;
1414 #elif defined(EPROTO)
1415 *perrno = EPROTO;
1416 #else
1417 *perrno = EINVAL;
1418 #endif
1419 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1420 nt_errstr(state->accept_status),
1421 strerror(*perrno)));
1422 tevent_req_received(req);
1423 return -1;
1426 *stream = tstream_context_create(mem_ctx,
1427 &tstream_npa_ops,
1428 &npas,
1429 struct tstream_npa,
1430 location);
1431 if (!*stream) {
1432 *perrno = ENOMEM;
1433 tevent_req_received(req);
1434 return -1;
1436 ZERO_STRUCTP(npas);
1437 npas->unix_stream = state->plain;
1438 npas->file_type = state->file_type;
1440 *remote_client_addr = talloc_move(mem_ctx, &state->remote_client_addr);
1441 *_remote_client_name = talloc_move(mem_ctx, &state->remote_client_name);
1442 *local_server_addr = talloc_move(mem_ctx, &state->local_server_addr);
1443 *local_server_name = talloc_move(mem_ctx, &state->local_server_name);
1444 *session_info = talloc_move(mem_ctx, &state->session_info);
1446 tevent_req_received(req);
1447 return 0;
1451 /* SOCKETPAIR for internal rpc communication */
1453 /* file_type is FILE_TYPE_BYTE_MODE_PIPE or FILE_TYPE_MESSAGE_MODE_PIPE */
1454 int _tstream_npa_socketpair(uint16_t file_type,
1455 TALLOC_CTX *mem_ctx1,
1456 struct tstream_context **pstream1,
1457 TALLOC_CTX *mem_ctx2,
1458 struct tstream_context **pstream2,
1459 const char *location)
1461 struct tstream_context *stream1 = NULL;
1462 struct tstream_context *stream2 = NULL;
1463 int fds[2];
1464 int fd1;
1465 int fd2;
1466 int rc;
1467 bool ok;
1469 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
1470 if (rc == -1) {
1471 return -1;
1473 fd1 = fds[0];
1474 fd2 = fds[1];
1476 ok = smb_set_close_on_exec(fd1);
1477 if (!ok) {
1478 goto close_fail;
1481 ok = smb_set_close_on_exec(fd2);
1482 if (!ok) {
1483 goto close_fail;
1486 rc = set_blocking(fd1, false);
1487 if (rc == -1) {
1488 goto close_fail;
1491 rc = set_blocking(fd2, false);
1492 if (rc == -1) {
1493 goto close_fail;
1496 rc = _tstream_npa_existing_socket(mem_ctx1,
1497 fd1,
1498 file_type,
1499 &stream1,
1500 location);
1501 if (rc == -1) {
1502 goto close_fail;
1505 rc = _tstream_npa_existing_socket(mem_ctx2,
1506 fd2,
1507 file_type,
1508 &stream2,
1509 location);
1510 if (rc == -1) {
1511 int sys_errno = errno;
1512 talloc_free(stream1);
1513 close(fd2);
1514 errno = sys_errno;
1515 return -1;
1518 *pstream1 = stream1;
1519 *pstream2 = stream2;
1521 return 0;
1523 close_fail:
1525 int sys_errno = errno;
1526 close(fd1);
1527 close(fd2);
1528 errno = sys_errno;
1529 return -1;