s3-security: use shared SECINFO_GROUP define.
[Samba/ekacnet.git] / libcli / named_pipe_auth / npa_tstream.c
blob0834c7dda68b140c4dbc6f3358da07c93c32fbb9
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2009
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../util/tevent_unix.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
26 #include "../libcli/named_pipe_auth/npa_tstream.h"
27 #include "libcli/raw/smb.h"
29 static const struct tstream_context_ops tstream_npa_ops;
31 struct tstream_npa {
32 struct tstream_context *unix_stream;
34 uint16_t file_type;
36 struct iovec pending;
39 struct tstream_npa_connect_state {
40 struct {
41 struct tevent_context *ev;
42 } 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 netr_SamInfo3 *sam_info3,
68 DATA_BLOB session_key,
69 DATA_BLOB delegated_creds)
71 struct tevent_req *req;
72 struct tstream_npa_connect_state *state;
73 struct tevent_req *subreq;
74 int ret;
75 enum ndr_err_code ndr_err;
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 state->unix_path = talloc_asprintf(state, "%s/%s",
86 directory,
87 npipe);
88 if (tevent_req_nomem(state->unix_path, req)) {
89 goto post;
92 ret = tsocket_address_unix_from_path(state,
93 "",
94 &state->unix_laddr);
95 if (ret == -1) {
96 tevent_req_error(req, errno);
97 goto post;
100 ret = tsocket_address_unix_from_path(state,
101 state->unix_path,
102 &state->unix_raddr);
103 if (ret == -1) {
104 tevent_req_error(req, errno);
105 goto post;
108 ZERO_STRUCT(state->auth_req);
109 if (client) {
110 struct named_pipe_auth_req_info3 *info3;
112 if (!server) {
113 tevent_req_error(req, EINVAL);
114 goto post;
117 state->auth_req.level = 3;
118 info3 = &state->auth_req.info.info3;
120 info3->client_name = client_name_in;
121 info3->client_addr = tsocket_address_inet_addr_string(client, state);
122 if (!info3->client_addr) {
123 /* errno might be EINVAL */
124 tevent_req_error(req, errno);
125 goto post;
127 info3->client_port = tsocket_address_inet_port(client);
128 if (!info3->client_name) {
129 info3->client_name = info3->client_addr;
132 info3->server_addr = tsocket_address_inet_addr_string(server, state);
133 if (!info3->server_addr) {
134 /* errno might be EINVAL */
135 tevent_req_error(req, errno);
136 goto post;
138 info3->server_port = tsocket_address_inet_port(server);
139 if (!info3->server_name) {
140 info3->server_name = info3->server_addr;
143 info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3);
144 info3->session_key_length = session_key.length;
145 info3->session_key = session_key.data;
146 info3->gssapi_delegated_creds_length = delegated_creds.length;
147 info3->gssapi_delegated_creds = delegated_creds.data;
149 } else if (sam_info3) {
150 state->auth_req.level = 1;
151 state->auth_req.info.info1 = *sam_info3;
152 } else {
153 state->auth_req.level = 0;
156 if (DEBUGLVL(10)) {
157 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
160 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
161 state, &state->auth_req,
162 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
163 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
164 tevent_req_error(req, EINVAL);
165 goto post;
168 state->auth_req_iov.iov_base = state->auth_req_blob.data;
169 state->auth_req_iov.iov_len = state->auth_req_blob.length;
171 subreq = tstream_unix_connect_send(state,
172 state->caller.ev,
173 state->unix_laddr,
174 state->unix_raddr);
175 if (tevent_req_nomem(subreq, req)) {
176 goto post;
178 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
180 return req;
182 post:
183 tevent_req_post(req, ev);
184 return req;
187 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
189 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
191 struct tevent_req *req =
192 tevent_req_callback_data(subreq,
193 struct tevent_req);
194 struct tstream_npa_connect_state *state =
195 tevent_req_data(req,
196 struct tstream_npa_connect_state);
197 int ret;
198 int sys_errno;
200 ret = tstream_unix_connect_recv(subreq, &sys_errno,
201 state, &state->unix_stream);
202 TALLOC_FREE(subreq);
203 if (ret == -1) {
204 tevent_req_error(req, sys_errno);
205 return;
208 subreq = tstream_writev_send(state,
209 state->caller.ev,
210 state->unix_stream,
211 &state->auth_req_iov, 1);
212 if (tevent_req_nomem(subreq, req)) {
213 return;
215 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
218 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
219 void *private_data,
220 TALLOC_CTX *mem_ctx,
221 struct iovec **_vector,
222 size_t *_count);
223 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
225 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
227 struct tevent_req *req =
228 tevent_req_callback_data(subreq,
229 struct tevent_req);
230 struct tstream_npa_connect_state *state =
231 tevent_req_data(req,
232 struct tstream_npa_connect_state);
233 int ret;
234 int sys_errno;
236 ret = tstream_writev_recv(subreq, &sys_errno);
237 TALLOC_FREE(subreq);
238 if (ret == -1) {
239 tevent_req_error(req, sys_errno);
240 return;
243 state->auth_rep_blob = data_blob_const(NULL, 0);
245 subreq = tstream_readv_pdu_send(state, state->caller.ev,
246 state->unix_stream,
247 tstream_npa_connect_next_vector,
248 state);
249 if (tevent_req_nomem(subreq, req)) {
250 return;
252 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
255 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
256 void *private_data,
257 TALLOC_CTX *mem_ctx,
258 struct iovec **_vector,
259 size_t *_count)
261 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
262 struct tstream_npa_connect_state);
263 struct iovec *vector;
264 size_t count;
265 off_t ofs = 0;
267 if (state->auth_rep_blob.length == 0) {
268 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
269 if (!state->auth_rep_blob.data) {
270 return -1;
272 } else if (state->auth_rep_blob.length == 4) {
273 uint32_t msg_len;
275 ofs = 4;
277 msg_len = RIVAL(state->auth_rep_blob.data, 0);
279 if (msg_len > 0x00FFFFFF) {
280 errno = EMSGSIZE;
281 return -1;
284 if (msg_len == 0) {
285 errno = EMSGSIZE;
286 return -1;
289 msg_len += ofs;
291 state->auth_rep_blob.data = talloc_realloc(state,
292 state->auth_rep_blob.data,
293 uint8_t, msg_len);
294 if (!state->auth_rep_blob.data) {
295 return -1;
297 state->auth_rep_blob.length = msg_len;
298 } else {
299 *_vector = NULL;
300 *_count = 0;
301 return 0;
304 /* we need to get a message header */
305 vector = talloc_array(mem_ctx, struct iovec, 1);
306 if (!vector) {
307 return -1;
309 vector[0].iov_base = state->auth_rep_blob.data + ofs;
310 vector[0].iov_len = state->auth_rep_blob.length - ofs;
311 count = 1;
313 *_vector = vector;
314 *_count = count;
315 return 0;
318 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
320 struct tevent_req *req =
321 tevent_req_callback_data(subreq,
322 struct tevent_req);
323 struct tstream_npa_connect_state *state =
324 tevent_req_data(req,
325 struct tstream_npa_connect_state);
326 int ret;
327 int sys_errno;
328 enum ndr_err_code ndr_err;
330 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
331 TALLOC_FREE(subreq);
332 if (ret == -1) {
333 tevent_req_error(req, sys_errno);
334 return;
337 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
338 (uint32_t)state->auth_rep_blob.length));
339 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
341 ndr_err = ndr_pull_struct_blob(
342 &state->auth_rep_blob, state,
343 &state->auth_rep,
344 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
346 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
347 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
348 ndr_map_error2string(ndr_err)));
349 tevent_req_error(req, EIO);
350 return;
353 if (DEBUGLVL(10)) {
354 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
357 if (state->auth_rep.length < 16) {
358 DEBUG(0, ("req invalid length: %u < 16\n",
359 state->auth_rep.length));
360 tevent_req_error(req, EIO);
361 return;
364 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
365 DEBUG(0, ("req invalid magic: %s != %s\n",
366 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
367 tevent_req_error(req, EIO);
368 return;
371 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
372 DEBUG(0, ("req failed: %s\n",
373 nt_errstr(state->auth_rep.status)));
374 tevent_req_error(req, EACCES);
375 return;
378 if (state->auth_rep.level != state->auth_req.level) {
379 DEBUG(0, ("req invalid level: %u != %u\n",
380 state->auth_rep.level, state->auth_req.level));
381 tevent_req_error(req, EIO);
382 return;
385 tevent_req_done(req);
388 int _tstream_npa_connect_recv(struct tevent_req *req,
389 int *perrno,
390 TALLOC_CTX *mem_ctx,
391 struct tstream_context **_stream,
392 uint16_t *_file_type,
393 uint16_t *_device_state,
394 uint64_t *_allocation_size,
395 const char *location)
397 struct tstream_npa_connect_state *state =
398 tevent_req_data(req,
399 struct tstream_npa_connect_state);
400 struct tstream_context *stream;
401 struct tstream_npa *npas;
402 uint16_t device_state = 0;
403 uint64_t allocation_size = 0;
405 if (tevent_req_is_unix_error(req, perrno)) {
406 tevent_req_received(req);
407 return -1;
410 stream = tstream_context_create(mem_ctx,
411 &tstream_npa_ops,
412 &npas,
413 struct tstream_npa,
414 location);
415 if (!stream) {
416 return -1;
418 ZERO_STRUCTP(npas);
420 npas->unix_stream = talloc_move(stream, &state->unix_stream);
421 switch (state->auth_rep.level) {
422 case 0:
423 case 1:
424 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
425 device_state = 0x00ff;
426 allocation_size = 2048;
427 break;
428 case 2:
429 npas->file_type = state->auth_rep.info.info2.file_type;
430 device_state = state->auth_rep.info.info2.device_state;
431 allocation_size = state->auth_rep.info.info2.allocation_size;
432 break;
433 case 3:
434 npas->file_type = state->auth_rep.info.info3.file_type;
435 device_state = state->auth_rep.info.info3.device_state;
436 allocation_size = state->auth_rep.info.info3.allocation_size;
437 break;
440 *_stream = stream;
441 *_file_type = npas->file_type;
442 *_device_state = device_state;
443 *_allocation_size = allocation_size;
444 tevent_req_received(req);
445 return 0;
448 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
450 struct tstream_npa *npas = tstream_context_data(stream,
451 struct tstream_npa);
452 ssize_t ret;
454 if (!npas->unix_stream) {
455 errno = ENOTCONN;
456 return -1;
459 switch (npas->file_type) {
460 case FILE_TYPE_BYTE_MODE_PIPE:
461 ret = tstream_pending_bytes(npas->unix_stream);
462 break;
464 case FILE_TYPE_MESSAGE_MODE_PIPE:
465 ret = npas->pending.iov_len;
466 break;
468 default:
469 ret = -1;
472 return ret;
475 struct tstream_npa_readv_state {
476 struct tstream_context *stream;
478 struct iovec *vector;
479 size_t count;
481 /* the header for message mode */
482 uint8_t hdr[2];
483 bool wait_for_hdr;
485 int ret;
488 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
489 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
490 void *private_data,
491 TALLOC_CTX *mem_ctx,
492 struct iovec **_vector,
493 size_t *_count);
494 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
496 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
497 struct tevent_context *ev,
498 struct tstream_context *stream,
499 struct iovec *vector,
500 size_t count)
502 struct tevent_req *req;
503 struct tstream_npa_readv_state *state;
504 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
505 struct tevent_req *subreq;
506 off_t ofs;
507 size_t left;
508 uint8_t *pbase;
510 req = tevent_req_create(mem_ctx, &state,
511 struct tstream_npa_readv_state);
512 if (!req) {
513 return NULL;
516 state->stream = stream;
517 state->ret = 0;
519 if (!npas->unix_stream) {
520 tevent_req_error(req, ENOTCONN);
521 goto post;
524 switch (npas->file_type) {
525 case FILE_TYPE_BYTE_MODE_PIPE:
526 state->vector = vector;
527 state->count = count;
529 subreq = tstream_readv_send(state,
531 npas->unix_stream,
532 state->vector,
533 state->count);
534 if (tevent_req_nomem(subreq,req)) {
535 goto post;
537 tevent_req_set_callback(subreq,
538 tstream_npa_readv_byte_mode_handler,
539 req);
541 return req;
543 case FILE_TYPE_MESSAGE_MODE_PIPE:
545 * we make a copy of the vector and prepend a header
546 * with the length
548 state->vector = talloc_array(state, struct iovec, count);
549 if (tevent_req_nomem(state->vector, req)) {
550 goto post;
552 memcpy(state->vector, vector, sizeof(struct iovec)*count);
553 state->count = count;
556 * copy the pending buffer first
558 ofs = 0;
559 left = npas->pending.iov_len;
560 pbase = (uint8_t *)npas->pending.iov_base;
562 while (left > 0 && state->count > 0) {
563 uint8_t *base;
564 base = (uint8_t *)state->vector[0].iov_base;
565 if (left < state->vector[0].iov_len) {
566 memcpy(base, pbase + ofs, left);
568 base += left;
569 state->vector[0].iov_base = base;
570 state->vector[0].iov_len -= left;
572 ofs += left;
573 left = 0;
574 TALLOC_FREE(pbase);
575 ZERO_STRUCT(npas->pending);
576 break;
578 memcpy(base, pbase + ofs, state->vector[0].iov_len);
580 ofs += state->vector[0].iov_len;
581 left -= state->vector[0].iov_len;
582 state->vector += 1;
583 state->count -= 1;
585 if (left == 0) {
586 TALLOC_FREE(pbase);
587 ZERO_STRUCT(npas->pending);
588 break;
592 if (left > 0) {
593 memmove(pbase, pbase + ofs, left);
594 npas->pending.iov_base = pbase;
595 npas->pending.iov_len = left;
597 * this cannot fail and even if it
598 * fails we can handle it
600 pbase = talloc_realloc(npas, pbase, uint8_t, left);
601 if (pbase) {
602 npas->pending.iov_base = pbase;
604 pbase = NULL;
607 state->ret += ofs;
609 if (state->count == 0) {
610 tevent_req_done(req);
611 goto post;
614 ZERO_STRUCT(state->hdr);
615 state->wait_for_hdr = false;
617 subreq = tstream_readv_pdu_send(state,
619 npas->unix_stream,
620 tstream_npa_readv_next_vector,
621 state);
622 if (tevent_req_nomem(subreq, req)) {
623 goto post;
625 tevent_req_set_callback(subreq,
626 tstream_npa_readv_msg_mode_handler,
627 req);
629 return req;
632 /* this can't happen */
633 tevent_req_error(req, EINVAL);
634 goto post;
636 post:
637 tevent_req_post(req, ev);
638 return req;
641 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
643 struct tevent_req *req = tevent_req_callback_data(subreq,
644 struct tevent_req);
645 struct tstream_npa_readv_state *state = tevent_req_data(req,
646 struct tstream_npa_readv_state);
647 int ret;
648 int sys_errno;
650 ret = tstream_readv_recv(subreq, &sys_errno);
651 TALLOC_FREE(subreq);
652 if (ret == -1) {
653 tevent_req_error(req, sys_errno);
654 return;
657 state->ret = ret;
659 tevent_req_done(req);
662 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
663 void *private_data,
664 TALLOC_CTX *mem_ctx,
665 struct iovec **_vector,
666 size_t *_count)
668 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
669 struct tstream_npa_readv_state);
670 struct tstream_npa *npas = tstream_context_data(state->stream,
671 struct tstream_npa);
672 struct iovec *vector;
673 size_t count;
674 uint16_t msg_len;
675 size_t left;
677 if (state->count == 0) {
678 *_vector = NULL;
679 *_count = 0;
680 return 0;
683 if (!state->wait_for_hdr) {
684 /* we need to get a message header */
685 vector = talloc_array(mem_ctx, struct iovec, 1);
686 if (!vector) {
687 return -1;
689 ZERO_STRUCT(state->hdr);
690 vector[0].iov_base = state->hdr;
691 vector[0].iov_len = sizeof(state->hdr);
693 count = 1;
695 state->wait_for_hdr = true;
697 *_vector = vector;
698 *_count = count;
699 return 0;
702 /* and now fill the callers buffers and maybe the pending buffer */
703 state->wait_for_hdr = false;
705 msg_len = SVAL(state->hdr, 0);
707 if (msg_len == 0) {
708 errno = EIO;
709 return -1;
712 state->wait_for_hdr = false;
714 /* +1 because we may need to fill the pending buffer */
715 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
716 if (!vector) {
717 return -1;
720 count = 0;
721 left = msg_len;
722 while (left > 0 && state->count > 0) {
723 if (left < state->vector[0].iov_len) {
724 uint8_t *base;
725 base = (uint8_t *)state->vector[0].iov_base;
726 vector[count].iov_base = base;
727 vector[count].iov_len = left;
728 count++;
729 base += left;
730 state->vector[0].iov_base = base;
731 state->vector[0].iov_len -= left;
732 break;
734 vector[count] = state->vector[0];
735 count++;
736 left -= state->vector[0].iov_len;
737 state->vector += 1;
738 state->count -= 1;
741 if (left > 0) {
743 * if the message is longer than the buffers the caller
744 * requested, we need to consume the rest of the message
745 * into the pending buffer, where the next readv can
746 * be served from.
748 npas->pending.iov_base = talloc_array(npas, uint8_t, left);
749 if (!npas->pending.iov_base) {
750 return -1;
752 npas->pending.iov_len = left;
754 vector[count] = npas->pending;
755 count++;
758 state->ret += (msg_len - left);
760 *_vector = vector;
761 *_count = count;
762 return 0;
765 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
767 struct tevent_req *req = tevent_req_callback_data(subreq,
768 struct tevent_req);
769 int ret;
770 int sys_errno;
772 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
773 TALLOC_FREE(subreq);
774 if (ret == -1) {
775 tevent_req_error(req, sys_errno);
776 return;
780 * we do not set state->ret here as ret includes the headr size.
781 * we set it in tstream_npa_readv_pdu_next_vector()
784 tevent_req_done(req);
787 static int tstream_npa_readv_recv(struct tevent_req *req,
788 int *perrno)
790 struct tstream_npa_readv_state *state = tevent_req_data(req,
791 struct tstream_npa_readv_state);
792 int ret;
794 ret = tsocket_simple_int_recv(req, perrno);
795 if (ret == 0) {
796 ret = state->ret;
799 tevent_req_received(req);
800 return ret;
803 struct tstream_npa_writev_state {
804 const struct iovec *vector;
805 size_t count;
807 /* the header for message mode */
808 bool hdr_used;
809 uint8_t hdr[2];
811 int ret;
814 static void tstream_npa_writev_handler(struct tevent_req *subreq);
816 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
817 struct tevent_context *ev,
818 struct tstream_context *stream,
819 const struct iovec *vector,
820 size_t count)
822 struct tevent_req *req;
823 struct tstream_npa_writev_state *state;
824 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
825 struct tevent_req *subreq;
826 size_t msg_len;
827 size_t i;
828 struct iovec *new_vector;
830 req = tevent_req_create(mem_ctx, &state,
831 struct tstream_npa_writev_state);
832 if (!req) {
833 return NULL;
836 state->ret = 0;
838 if (!npas->unix_stream) {
839 tevent_req_error(req, ENOTCONN);
840 goto post;
843 switch (npas->file_type) {
844 case FILE_TYPE_BYTE_MODE_PIPE:
845 state->hdr_used = false;
846 state->vector = vector;
847 state->count = count;
848 break;
850 case FILE_TYPE_MESSAGE_MODE_PIPE:
852 * we make a copy of the vector and prepend a header
853 * with the length
855 new_vector = talloc_array(state, struct iovec, count + 1);
856 if (tevent_req_nomem(new_vector, req)) {
857 goto post;
859 new_vector[0].iov_base = state->hdr;
860 new_vector[0].iov_len = sizeof(state->hdr);
861 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
863 state->hdr_used = true;
864 state->vector = new_vector;
865 state->count = count + 1;
867 msg_len = 0;
868 for (i=0; i < count; i++) {
869 msg_len += vector[i].iov_len;
872 if (msg_len > UINT16_MAX) {
873 tevent_req_error(req, EMSGSIZE);
874 goto post;
877 SSVAL(state->hdr, 0, msg_len);
878 break;
881 subreq = tstream_writev_send(state,
883 npas->unix_stream,
884 state->vector,
885 state->count);
886 if (tevent_req_nomem(subreq, req)) {
887 goto post;
889 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
891 return req;
893 post:
894 tevent_req_post(req, ev);
895 return req;
898 static void tstream_npa_writev_handler(struct tevent_req *subreq)
900 struct tevent_req *req = tevent_req_callback_data(subreq,
901 struct tevent_req);
902 struct tstream_npa_writev_state *state = tevent_req_data(req,
903 struct tstream_npa_writev_state);
904 int ret;
905 int sys_errno;
907 ret = tstream_writev_recv(subreq, &sys_errno);
908 TALLOC_FREE(subreq);
909 if (ret == -1) {
910 tevent_req_error(req, sys_errno);
911 return;
915 * in message mode we need to hide the length
916 * of the hdr from the caller
918 if (state->hdr_used) {
919 ret -= sizeof(state->hdr);
922 state->ret = ret;
924 tevent_req_done(req);
927 static int tstream_npa_writev_recv(struct tevent_req *req,
928 int *perrno)
930 struct tstream_npa_writev_state *state = tevent_req_data(req,
931 struct tstream_npa_writev_state);
932 int ret;
934 ret = tsocket_simple_int_recv(req, perrno);
935 if (ret == 0) {
936 ret = state->ret;
939 tevent_req_received(req);
940 return ret;
943 struct tstream_npa_disconnect_state {
944 struct tstream_context *stream;
947 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
949 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
950 struct tevent_context *ev,
951 struct tstream_context *stream)
953 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
954 struct tevent_req *req;
955 struct tstream_npa_disconnect_state *state;
956 struct tevent_req *subreq;
958 req = tevent_req_create(mem_ctx, &state,
959 struct tstream_npa_disconnect_state);
960 if (req == NULL) {
961 return NULL;
964 state->stream = stream;
966 if (!npas->unix_stream) {
967 tevent_req_error(req, ENOTCONN);
968 goto post;
971 subreq = tstream_disconnect_send(state,
973 npas->unix_stream);
974 if (tevent_req_nomem(subreq, req)) {
975 goto post;
977 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
979 return req;
981 post:
982 tevent_req_post(req, ev);
983 return req;
986 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
988 struct tevent_req *req = tevent_req_callback_data(subreq,
989 struct tevent_req);
990 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
991 struct tstream_npa_disconnect_state);
992 struct tstream_context *stream = state->stream;
993 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
994 int ret;
995 int sys_errno;
997 ret = tstream_disconnect_recv(subreq, &sys_errno);
998 TALLOC_FREE(subreq);
999 if (ret == -1) {
1000 tevent_req_error(req, sys_errno);
1001 return;
1004 TALLOC_FREE(npas->unix_stream);
1006 tevent_req_done(req);
1009 static int tstream_npa_disconnect_recv(struct tevent_req *req,
1010 int *perrno)
1012 int ret;
1014 ret = tsocket_simple_int_recv(req, perrno);
1016 tevent_req_received(req);
1017 return ret;
1020 static const struct tstream_context_ops tstream_npa_ops = {
1021 .name = "npa",
1023 .pending_bytes = tstream_npa_pending_bytes,
1025 .readv_send = tstream_npa_readv_send,
1026 .readv_recv = tstream_npa_readv_recv,
1028 .writev_send = tstream_npa_writev_send,
1029 .writev_recv = tstream_npa_writev_recv,
1031 .disconnect_send = tstream_npa_disconnect_send,
1032 .disconnect_recv = tstream_npa_disconnect_recv,
1035 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1036 int fd,
1037 uint16_t file_type,
1038 struct tstream_context **_stream,
1039 const char *location)
1041 struct tstream_context *stream;
1042 struct tstream_npa *npas;
1043 int ret;
1045 switch (file_type) {
1046 case FILE_TYPE_BYTE_MODE_PIPE:
1047 break;
1048 case FILE_TYPE_MESSAGE_MODE_PIPE:
1049 break;
1050 default:
1051 errno = EINVAL;
1052 return -1;
1055 stream = tstream_context_create(mem_ctx,
1056 &tstream_npa_ops,
1057 &npas,
1058 struct tstream_npa,
1059 location);
1060 if (!stream) {
1061 return -1;
1063 ZERO_STRUCTP(npas);
1065 npas->file_type = file_type;
1067 ret = tstream_bsd_existing_socket(stream, fd,
1068 &npas->unix_stream);
1069 if (ret == -1) {
1070 int saved_errno = errno;
1071 talloc_free(stream);
1072 errno = saved_errno;
1073 return -1;
1076 *_stream = stream;
1077 return 0;
1081 struct tstream_npa_accept_state {
1082 struct tevent_context *ev;
1083 struct tstream_context *plain;
1084 uint16_t file_type;
1085 uint16_t device_state;
1086 uint64_t alloc_size;
1088 DATA_BLOB npa_blob;
1089 struct iovec out_iov;
1091 /* results */
1092 NTSTATUS accept_status;
1093 struct tsocket_address *client;
1094 char *client_name;
1095 struct tsocket_address *server;
1096 char *server_name;
1097 struct netr_SamInfo3 *info3;
1098 DATA_BLOB session_key;
1099 DATA_BLOB delegated_creds;
1102 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1103 void *private_data,
1104 TALLOC_CTX *mem_ctx,
1105 struct iovec **_vector,
1106 size_t *_count);
1107 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1108 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1110 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1111 struct tevent_context *ev,
1112 struct tstream_context *plain,
1113 uint16_t file_type,
1114 uint16_t device_state,
1115 uint64_t allocation_size)
1117 struct tstream_npa_accept_state *state;
1118 struct tevent_req *req, *subreq;
1120 req = tevent_req_create(mem_ctx, &state,
1121 struct tstream_npa_accept_state);
1122 if (req == NULL) {
1123 return NULL;
1126 switch (file_type) {
1127 case FILE_TYPE_BYTE_MODE_PIPE:
1128 break;
1129 case FILE_TYPE_MESSAGE_MODE_PIPE:
1130 break;
1131 default:
1132 tevent_req_error(req, EINVAL);
1133 goto post;
1136 ZERO_STRUCTP(state);
1138 state->ev = ev;
1139 state->plain = plain;
1140 state->file_type = file_type;
1141 state->device_state = device_state;
1142 state->alloc_size = allocation_size;
1145 * The named pipe pdu's have the length as 8 byte (initial_read_size),
1146 * named_pipe_full_request provides the pdu length then.
1148 subreq = tstream_readv_pdu_send(state, ev, plain,
1149 tstream_npa_accept_next_vector,
1150 state);
1151 if (tevent_req_nomem(subreq, req)) {
1152 goto post;
1155 tevent_req_set_callback(subreq,
1156 tstream_npa_accept_existing_reply, req);
1158 return req;
1160 post:
1161 tevent_req_post(req, ev);
1162 return req;
1165 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1166 void *private_data,
1167 TALLOC_CTX *mem_ctx,
1168 struct iovec **_vector,
1169 size_t *_count)
1171 struct tstream_npa_accept_state *state =
1172 talloc_get_type_abort(private_data,
1173 struct tstream_npa_accept_state);
1174 struct iovec *vector;
1175 size_t count;
1176 off_t ofs = 0;
1178 if (state->npa_blob.length == 0) {
1179 state->npa_blob = data_blob_talloc(state, NULL, 4);
1180 if (!state->npa_blob.data) {
1181 return -1;
1183 } else if (state->npa_blob.length == 4) {
1184 uint32_t msg_len;
1186 ofs = 4;
1188 msg_len = RIVAL(state->npa_blob.data, 0);
1190 if (msg_len > 0x00FFFFFF) {
1191 errno = EMSGSIZE;
1192 return -1;
1195 if (msg_len == 0) {
1196 errno = EMSGSIZE;
1197 return -1;
1200 msg_len += ofs;
1202 state->npa_blob.data = talloc_realloc(state,
1203 state->npa_blob.data,
1204 uint8_t, msg_len);
1205 if (!state->npa_blob.data) {
1206 return -1;
1208 state->npa_blob.length = msg_len;
1209 } else {
1210 if (memcmp(&state->npa_blob.data[4],
1211 NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1212 DEBUG(0, ("Wrong protocol\n"));
1213 #if defined(EPROTONOSUPPORT)
1214 errno = EPROTONOSUPPORT;
1215 #elif defined(EPROTO)
1216 errno = EPROTO;
1217 #else
1218 errno = EINVAL;
1219 #endif
1220 return -1;
1222 *_vector = NULL;
1223 *_count = 0;
1224 return 0;
1227 /* we need to get a message header */
1228 vector = talloc_array(mem_ctx, struct iovec, 1);
1229 if (!vector) {
1230 return -1;
1232 vector[0].iov_base = state->npa_blob.data + ofs;
1233 vector[0].iov_len = state->npa_blob.length - ofs;
1234 count = 1;
1236 *_vector = vector;
1237 *_count = count;
1238 return 0;
1241 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1243 struct tevent_req *req =
1244 tevent_req_callback_data(subreq, struct tevent_req);
1245 struct tstream_npa_accept_state *state =
1246 tevent_req_data(req, struct tstream_npa_accept_state);
1247 struct named_pipe_auth_req *pipe_request;
1248 struct named_pipe_auth_rep pipe_reply;
1249 struct named_pipe_auth_req_info3 i3;
1250 enum ndr_err_code ndr_err;
1251 DATA_BLOB out;
1252 int sys_errno;
1253 int ret;
1255 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1256 TALLOC_FREE(subreq);
1257 if (ret == -1) {
1258 tevent_req_error(req, sys_errno);
1259 return;
1262 DEBUG(10, ("Received packet of length %lu\n",
1263 (long)state->npa_blob.length));
1264 dump_data(11, state->npa_blob.data, state->npa_blob.length);
1266 ZERO_STRUCT(pipe_reply);
1267 pipe_reply.level = 0;
1268 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1270 * TODO: check it's a root (uid == 0) pipe
1273 pipe_request = talloc(state, struct named_pipe_auth_req);
1274 if (!pipe_request) {
1275 DEBUG(0, ("Out of memory!\n"));
1276 goto reply;
1279 /* parse the passed credentials */
1280 ndr_err = ndr_pull_struct_blob_all(
1281 &state->npa_blob, pipe_request, pipe_request,
1282 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1283 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1284 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1285 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1286 nt_errstr(pipe_reply.status)));
1287 goto reply;
1290 if (DEBUGLVL(10)) {
1291 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1294 ZERO_STRUCT(i3);
1296 switch (pipe_request->level) {
1297 case 0:
1298 pipe_reply.level = 0;
1299 pipe_reply.status = NT_STATUS_OK;
1301 /* we need to force byte mode in this level */
1302 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1303 break;
1305 case 1:
1306 pipe_reply.level = 1;
1307 pipe_reply.status = NT_STATUS_OK;
1309 /* We must copy net3_SamInfo3, so that
1310 * info3 is an actual talloc pointer, then we steal
1311 * pipe_request on info3 so that all the allocated memory
1312 * pointed by the structrue members is preserved */
1313 state->info3 = (struct netr_SamInfo3 *)talloc_memdup(state,
1314 &pipe_request->info.info1,
1315 sizeof(struct netr_SamInfo3));
1316 if (!state->info3) {
1317 pipe_reply.status = NT_STATUS_NO_MEMORY;
1318 DEBUG(0, ("Out of memory!\n"));
1319 goto reply;
1321 talloc_move(state->info3, &pipe_request);
1323 /* we need to force byte mode in this level */
1324 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1325 break;
1327 case 2:
1328 pipe_reply.level = 2;
1329 pipe_reply.status = NT_STATUS_OK;
1330 pipe_reply.info.info2.file_type = state->file_type;
1331 pipe_reply.info.info2.device_state = state->device_state;
1332 pipe_reply.info.info2.allocation_size = state->alloc_size;
1334 i3.client_name = pipe_request->info.info2.client_name;
1335 i3.client_addr = pipe_request->info.info2.client_addr;
1336 i3.client_port = pipe_request->info.info2.client_port;
1337 i3.server_name = pipe_request->info.info2.server_name;
1338 i3.server_addr = pipe_request->info.info2.server_addr;
1339 i3.server_port = pipe_request->info.info2.server_port;
1340 i3.sam_info3 = pipe_request->info.info2.sam_info3;
1341 i3.session_key_length =
1342 pipe_request->info.info2.session_key_length;
1343 i3.session_key = pipe_request->info.info2.session_key;
1344 break;
1346 case 3:
1347 pipe_reply.level = 3;
1348 pipe_reply.status = NT_STATUS_OK;
1349 pipe_reply.info.info3.file_type = state->file_type;
1350 pipe_reply.info.info3.device_state = state->device_state;
1351 pipe_reply.info.info3.allocation_size = state->alloc_size;
1353 i3 = pipe_request->info.info3;
1354 break;
1356 default:
1357 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1358 pipe_reply.level = 0;
1359 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1360 goto reply;
1363 if (pipe_reply.level >=2) {
1365 if (i3.server_addr == NULL) {
1366 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1367 DEBUG(2, ("Missing server address\n"));
1368 goto reply;
1370 if (i3.client_addr == NULL) {
1371 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1372 DEBUG(2, ("Missing client address\n"));
1373 goto reply;
1376 state->server_name = discard_const_p(char,
1377 talloc_move(state, &i3.server_name));
1378 ret = tsocket_address_inet_from_strings(state, "ip",
1379 i3.server_addr,
1380 i3.server_port,
1381 &state->server);
1382 if (ret != 0) {
1383 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1384 i3.server_addr, i3.server_port,
1385 strerror(errno)));
1386 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1387 goto reply;
1390 state->client_name = discard_const_p(char,
1391 talloc_move(state, &i3.client_name));
1392 ret = tsocket_address_inet_from_strings(state, "ip",
1393 i3.client_addr,
1394 i3.client_port,
1395 &state->client);
1396 if (ret != 0) {
1397 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1398 i3.client_addr, i3.client_port,
1399 strerror(errno)));
1400 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1401 goto reply;
1404 state->info3 = talloc_move(state, &i3.sam_info3);
1405 state->session_key.data = talloc_move(state, &i3.session_key);
1406 state->session_key.length = i3.session_key_length;
1409 if (pipe_reply.level >= 3) {
1410 state->delegated_creds.data =
1411 talloc_move(state, &i3.gssapi_delegated_creds);
1412 state->delegated_creds.length =
1413 i3.gssapi_delegated_creds_length;
1416 reply:
1417 /* create the output */
1418 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1419 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1420 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1421 DEBUG(2, ("Error encoding structure: %s",
1422 ndr_map_error2string(ndr_err)));
1423 tevent_req_error(req, EIO);
1424 return;
1427 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1428 dump_data(11, out.data, out.length);
1430 if (DEBUGLVL(10)) {
1431 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1434 state->accept_status = pipe_reply.status;
1436 state->out_iov.iov_base = out.data;
1437 state->out_iov.iov_len = out.length;
1439 subreq = tstream_writev_send(state, state->ev,
1440 state->plain,
1441 &state->out_iov, 1);
1442 if (tevent_req_nomem(subreq, req)) {
1443 DEBUG(0, ("no memory for tstream_writev_send"));
1444 return;
1447 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1450 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1452 struct tevent_req *req =
1453 tevent_req_callback_data(subreq, struct tevent_req);
1454 int sys_errno;
1455 int ret;
1457 ret = tstream_writev_recv(subreq, &sys_errno);
1458 TALLOC_FREE(subreq);
1459 if (ret == -1) {
1460 tevent_req_error(req, sys_errno);
1461 return;
1464 tevent_req_done(req);
1467 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1468 int *perrno,
1469 TALLOC_CTX *mem_ctx,
1470 struct tstream_context **stream,
1471 struct tsocket_address **client,
1472 char **_client_name,
1473 struct tsocket_address **server,
1474 char **server_name,
1475 struct netr_SamInfo3 **info3,
1476 DATA_BLOB *session_key,
1477 DATA_BLOB *delegated_creds,
1478 const char *location)
1480 struct tstream_npa_accept_state *state =
1481 tevent_req_data(req, struct tstream_npa_accept_state);
1482 struct tstream_npa *npas;
1483 int ret;
1485 ret = tsocket_simple_int_recv(req, perrno);
1486 if (ret != 0) {
1487 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1488 strerror(*perrno)));
1489 tevent_req_received(req);
1490 return -1;
1493 if (!NT_STATUS_IS_OK(state->accept_status)) {
1494 #if defined(EPROTONOSUPPORT)
1495 *perrno = EPROTONOSUPPORT;
1496 #elif defined(EPROTO)
1497 *perrno = EPROTO;
1498 #else
1499 *perrno = EINVAL;
1500 #endif
1501 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1502 nt_errstr(state->accept_status),
1503 strerror(*perrno)));
1504 tevent_req_received(req);
1505 return -1;
1508 *stream = tstream_context_create(mem_ctx,
1509 &tstream_npa_ops,
1510 &npas,
1511 struct tstream_npa,
1512 location);
1513 if (!*stream) {
1514 *perrno = ENOMEM;
1515 tevent_req_received(req);
1516 return -1;
1518 ZERO_STRUCTP(npas);
1519 npas->unix_stream = state->plain;
1520 npas->file_type = state->file_type;
1522 *client = talloc_move(mem_ctx, &state->client);
1523 *_client_name = talloc_move(mem_ctx, &state->client_name);
1524 *server = talloc_move(mem_ctx, &state->server);
1525 *server_name = talloc_move(mem_ctx, &state->server_name);
1526 *info3 = talloc_move(mem_ctx, &state->info3);
1527 *session_key = state->session_key;
1528 talloc_move(mem_ctx, &state->session_key.data);
1529 *delegated_creds = state->delegated_creds;
1530 talloc_move(mem_ctx, &state->delegated_creds.data);
1532 tevent_req_received(req);
1533 return 0;