tsocket: fill in sa.sa_len if the system supports it
[Samba/gebeck_regimport.git] / libcli / named_pipe_auth / npa_tstream.c
blobb0ef11fdfb8f11c4bd093fc399aed71127cbd5da
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;
76 char *lower_case_npipe;
78 req = tevent_req_create(mem_ctx, &state,
79 struct tstream_npa_connect_state);
80 if (!req) {
81 return NULL;
84 state->caller.ev = ev;
86 lower_case_npipe = strlower_talloc(state, npipe);
87 if (tevent_req_nomem(lower_case_npipe, req)) {
88 goto post;
91 state->unix_path = talloc_asprintf(state, "%s/%s",
92 directory,
93 lower_case_npipe);
94 talloc_free(lower_case_npipe);
95 if (tevent_req_nomem(state->unix_path, req)) {
96 goto post;
99 ret = tsocket_address_unix_from_path(state,
101 &state->unix_laddr);
102 if (ret == -1) {
103 tevent_req_error(req, errno);
104 goto post;
107 ret = tsocket_address_unix_from_path(state,
108 state->unix_path,
109 &state->unix_raddr);
110 if (ret == -1) {
111 tevent_req_error(req, errno);
112 goto post;
115 ZERO_STRUCT(state->auth_req);
116 if (client) {
117 struct named_pipe_auth_req_info3 *info3;
119 if (!server) {
120 tevent_req_error(req, EINVAL);
121 goto post;
124 state->auth_req.level = 3;
125 info3 = &state->auth_req.info.info3;
127 info3->client_name = client_name_in;
128 info3->client_addr = tsocket_address_inet_addr_string(client, state);
129 if (!info3->client_addr) {
130 /* errno might be EINVAL */
131 tevent_req_error(req, errno);
132 goto post;
134 info3->client_port = tsocket_address_inet_port(client);
135 if (!info3->client_name) {
136 info3->client_name = info3->client_addr;
139 info3->server_addr = tsocket_address_inet_addr_string(server, state);
140 if (!info3->server_addr) {
141 /* errno might be EINVAL */
142 tevent_req_error(req, errno);
143 goto post;
145 info3->server_port = tsocket_address_inet_port(server);
146 if (!info3->server_name) {
147 info3->server_name = info3->server_addr;
150 info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3);
151 info3->session_key_length = session_key.length;
152 info3->session_key = session_key.data;
153 info3->gssapi_delegated_creds_length = delegated_creds.length;
154 info3->gssapi_delegated_creds = delegated_creds.data;
156 } else if (sam_info3) {
157 state->auth_req.level = 1;
158 state->auth_req.info.info1 = *sam_info3;
159 } else {
160 state->auth_req.level = 0;
163 if (DEBUGLVL(10)) {
164 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
167 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
168 state, &state->auth_req,
169 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
170 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
171 tevent_req_error(req, EINVAL);
172 goto post;
175 state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
176 state->auth_req_iov.iov_len = state->auth_req_blob.length;
178 subreq = tstream_unix_connect_send(state,
179 state->caller.ev,
180 state->unix_laddr,
181 state->unix_raddr);
182 if (tevent_req_nomem(subreq, req)) {
183 goto post;
185 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
187 return req;
189 post:
190 tevent_req_post(req, ev);
191 return req;
194 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
196 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
198 struct tevent_req *req =
199 tevent_req_callback_data(subreq,
200 struct tevent_req);
201 struct tstream_npa_connect_state *state =
202 tevent_req_data(req,
203 struct tstream_npa_connect_state);
204 int ret;
205 int sys_errno;
207 ret = tstream_unix_connect_recv(subreq, &sys_errno,
208 state, &state->unix_stream);
209 TALLOC_FREE(subreq);
210 if (ret == -1) {
211 tevent_req_error(req, sys_errno);
212 return;
215 subreq = tstream_writev_send(state,
216 state->caller.ev,
217 state->unix_stream,
218 &state->auth_req_iov, 1);
219 if (tevent_req_nomem(subreq, req)) {
220 return;
222 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
225 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
226 void *private_data,
227 TALLOC_CTX *mem_ctx,
228 struct iovec **_vector,
229 size_t *_count);
230 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
232 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
234 struct tevent_req *req =
235 tevent_req_callback_data(subreq,
236 struct tevent_req);
237 struct tstream_npa_connect_state *state =
238 tevent_req_data(req,
239 struct tstream_npa_connect_state);
240 int ret;
241 int sys_errno;
243 ret = tstream_writev_recv(subreq, &sys_errno);
244 TALLOC_FREE(subreq);
245 if (ret == -1) {
246 tevent_req_error(req, sys_errno);
247 return;
250 state->auth_rep_blob = data_blob_const(NULL, 0);
252 subreq = tstream_readv_pdu_send(state, state->caller.ev,
253 state->unix_stream,
254 tstream_npa_connect_next_vector,
255 state);
256 if (tevent_req_nomem(subreq, req)) {
257 return;
259 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
262 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
263 void *private_data,
264 TALLOC_CTX *mem_ctx,
265 struct iovec **_vector,
266 size_t *_count)
268 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
269 struct tstream_npa_connect_state);
270 struct iovec *vector;
271 size_t count;
272 off_t ofs = 0;
274 if (state->auth_rep_blob.length == 0) {
275 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
276 if (!state->auth_rep_blob.data) {
277 return -1;
279 } else if (state->auth_rep_blob.length == 4) {
280 uint32_t msg_len;
282 ofs = 4;
284 msg_len = RIVAL(state->auth_rep_blob.data, 0);
286 if (msg_len > 0x00FFFFFF) {
287 errno = EMSGSIZE;
288 return -1;
291 if (msg_len == 0) {
292 errno = EMSGSIZE;
293 return -1;
296 msg_len += ofs;
298 state->auth_rep_blob.data = talloc_realloc(state,
299 state->auth_rep_blob.data,
300 uint8_t, msg_len);
301 if (!state->auth_rep_blob.data) {
302 return -1;
304 state->auth_rep_blob.length = msg_len;
305 } else {
306 *_vector = NULL;
307 *_count = 0;
308 return 0;
311 /* we need to get a message header */
312 vector = talloc_array(mem_ctx, struct iovec, 1);
313 if (!vector) {
314 return -1;
316 vector[0].iov_base = (char *) (state->auth_rep_blob.data + ofs);
317 vector[0].iov_len = state->auth_rep_blob.length - ofs;
318 count = 1;
320 *_vector = vector;
321 *_count = count;
322 return 0;
325 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
327 struct tevent_req *req =
328 tevent_req_callback_data(subreq,
329 struct tevent_req);
330 struct tstream_npa_connect_state *state =
331 tevent_req_data(req,
332 struct tstream_npa_connect_state);
333 int ret;
334 int sys_errno;
335 enum ndr_err_code ndr_err;
337 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
338 TALLOC_FREE(subreq);
339 if (ret == -1) {
340 tevent_req_error(req, sys_errno);
341 return;
344 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
345 (uint32_t)state->auth_rep_blob.length));
346 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
348 ndr_err = ndr_pull_struct_blob(
349 &state->auth_rep_blob, state,
350 &state->auth_rep,
351 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
353 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
354 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
355 ndr_map_error2string(ndr_err)));
356 tevent_req_error(req, EIO);
357 return;
360 if (DEBUGLVL(10)) {
361 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
364 if (state->auth_rep.length < 16) {
365 DEBUG(0, ("req invalid length: %u < 16\n",
366 state->auth_rep.length));
367 tevent_req_error(req, EIO);
368 return;
371 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
372 DEBUG(0, ("req invalid magic: %s != %s\n",
373 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
374 tevent_req_error(req, EIO);
375 return;
378 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
379 DEBUG(0, ("req failed: %s\n",
380 nt_errstr(state->auth_rep.status)));
381 tevent_req_error(req, EACCES);
382 return;
385 if (state->auth_rep.level != state->auth_req.level) {
386 DEBUG(0, ("req invalid level: %u != %u\n",
387 state->auth_rep.level, state->auth_req.level));
388 tevent_req_error(req, EIO);
389 return;
392 tevent_req_done(req);
395 int _tstream_npa_connect_recv(struct tevent_req *req,
396 int *perrno,
397 TALLOC_CTX *mem_ctx,
398 struct tstream_context **_stream,
399 uint16_t *_file_type,
400 uint16_t *_device_state,
401 uint64_t *_allocation_size,
402 const char *location)
404 struct tstream_npa_connect_state *state =
405 tevent_req_data(req,
406 struct tstream_npa_connect_state);
407 struct tstream_context *stream;
408 struct tstream_npa *npas;
409 uint16_t device_state = 0;
410 uint64_t allocation_size = 0;
412 if (tevent_req_is_unix_error(req, perrno)) {
413 tevent_req_received(req);
414 return -1;
417 stream = tstream_context_create(mem_ctx,
418 &tstream_npa_ops,
419 &npas,
420 struct tstream_npa,
421 location);
422 if (!stream) {
423 *perrno = ENOMEM;
424 tevent_req_received(req);
425 return -1;
427 ZERO_STRUCTP(npas);
429 npas->unix_stream = talloc_move(stream, &state->unix_stream);
430 switch (state->auth_rep.level) {
431 case 0:
432 case 1:
433 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
434 device_state = 0x00ff;
435 allocation_size = 2048;
436 break;
437 case 2:
438 npas->file_type = state->auth_rep.info.info2.file_type;
439 device_state = state->auth_rep.info.info2.device_state;
440 allocation_size = state->auth_rep.info.info2.allocation_size;
441 break;
442 case 3:
443 npas->file_type = state->auth_rep.info.info3.file_type;
444 device_state = state->auth_rep.info.info3.device_state;
445 allocation_size = state->auth_rep.info.info3.allocation_size;
446 break;
449 *_stream = stream;
450 *_file_type = npas->file_type;
451 *_device_state = device_state;
452 *_allocation_size = allocation_size;
453 tevent_req_received(req);
454 return 0;
457 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
459 struct tstream_npa *npas = tstream_context_data(stream,
460 struct tstream_npa);
461 ssize_t ret;
463 if (!npas->unix_stream) {
464 errno = ENOTCONN;
465 return -1;
468 switch (npas->file_type) {
469 case FILE_TYPE_BYTE_MODE_PIPE:
470 ret = tstream_pending_bytes(npas->unix_stream);
471 break;
473 case FILE_TYPE_MESSAGE_MODE_PIPE:
474 ret = npas->pending.iov_len;
475 break;
477 default:
478 ret = -1;
481 return ret;
484 struct tstream_npa_readv_state {
485 struct tstream_context *stream;
487 struct iovec *vector;
488 size_t count;
490 /* the header for message mode */
491 uint8_t hdr[2];
492 bool wait_for_hdr;
494 int ret;
497 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
498 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
499 void *private_data,
500 TALLOC_CTX *mem_ctx,
501 struct iovec **_vector,
502 size_t *_count);
503 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
505 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
506 struct tevent_context *ev,
507 struct tstream_context *stream,
508 struct iovec *vector,
509 size_t count)
511 struct tevent_req *req;
512 struct tstream_npa_readv_state *state;
513 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
514 struct tevent_req *subreq;
515 off_t ofs;
516 size_t left;
517 uint8_t *pbase;
519 req = tevent_req_create(mem_ctx, &state,
520 struct tstream_npa_readv_state);
521 if (!req) {
522 return NULL;
525 state->stream = stream;
526 state->ret = 0;
528 if (!npas->unix_stream) {
529 tevent_req_error(req, ENOTCONN);
530 goto post;
533 switch (npas->file_type) {
534 case FILE_TYPE_BYTE_MODE_PIPE:
535 state->vector = vector;
536 state->count = count;
538 subreq = tstream_readv_send(state,
540 npas->unix_stream,
541 state->vector,
542 state->count);
543 if (tevent_req_nomem(subreq,req)) {
544 goto post;
546 tevent_req_set_callback(subreq,
547 tstream_npa_readv_byte_mode_handler,
548 req);
550 return req;
552 case FILE_TYPE_MESSAGE_MODE_PIPE:
554 * we make a copy of the vector and prepend a header
555 * with the length
557 state->vector = talloc_array(state, struct iovec, count);
558 if (tevent_req_nomem(state->vector, req)) {
559 goto post;
561 memcpy(state->vector, vector, sizeof(struct iovec)*count);
562 state->count = count;
565 * copy the pending buffer first
567 ofs = 0;
568 left = npas->pending.iov_len;
569 pbase = (uint8_t *)npas->pending.iov_base;
571 while (left > 0 && state->count > 0) {
572 uint8_t *base;
573 base = (uint8_t *)state->vector[0].iov_base;
574 if (left < state->vector[0].iov_len) {
575 memcpy(base, pbase + ofs, left);
577 base += left;
578 state->vector[0].iov_base = (char *) base;
579 state->vector[0].iov_len -= left;
581 ofs += left;
582 left = 0;
583 TALLOC_FREE(pbase);
584 ZERO_STRUCT(npas->pending);
585 break;
587 memcpy(base, pbase + ofs, state->vector[0].iov_len);
589 ofs += state->vector[0].iov_len;
590 left -= state->vector[0].iov_len;
591 state->vector += 1;
592 state->count -= 1;
594 if (left == 0) {
595 TALLOC_FREE(pbase);
596 ZERO_STRUCT(npas->pending);
597 break;
601 if (left > 0) {
602 memmove(pbase, pbase + ofs, left);
603 npas->pending.iov_base = (char *) pbase;
604 npas->pending.iov_len = left;
606 * this cannot fail and even if it
607 * fails we can handle it
609 pbase = talloc_realloc(npas, pbase, uint8_t, left);
610 if (pbase) {
611 npas->pending.iov_base = (char *) pbase;
613 pbase = NULL;
616 state->ret += ofs;
618 if (state->count == 0) {
619 tevent_req_done(req);
620 goto post;
623 ZERO_STRUCT(state->hdr);
624 state->wait_for_hdr = false;
626 subreq = tstream_readv_pdu_send(state,
628 npas->unix_stream,
629 tstream_npa_readv_next_vector,
630 state);
631 if (tevent_req_nomem(subreq, req)) {
632 goto post;
634 tevent_req_set_callback(subreq,
635 tstream_npa_readv_msg_mode_handler,
636 req);
638 return req;
641 /* this can't happen */
642 tevent_req_error(req, EINVAL);
643 goto post;
645 post:
646 tevent_req_post(req, ev);
647 return req;
650 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
652 struct tevent_req *req = tevent_req_callback_data(subreq,
653 struct tevent_req);
654 struct tstream_npa_readv_state *state = tevent_req_data(req,
655 struct tstream_npa_readv_state);
656 int ret;
657 int sys_errno;
659 ret = tstream_readv_recv(subreq, &sys_errno);
660 TALLOC_FREE(subreq);
661 if (ret == -1) {
662 tevent_req_error(req, sys_errno);
663 return;
666 state->ret = ret;
668 tevent_req_done(req);
671 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
672 void *private_data,
673 TALLOC_CTX *mem_ctx,
674 struct iovec **_vector,
675 size_t *_count)
677 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
678 struct tstream_npa_readv_state);
679 struct tstream_npa *npas = tstream_context_data(state->stream,
680 struct tstream_npa);
681 struct iovec *vector;
682 size_t count;
683 uint16_t msg_len;
684 size_t left;
686 if (state->count == 0) {
687 *_vector = NULL;
688 *_count = 0;
689 return 0;
692 if (!state->wait_for_hdr) {
693 /* we need to get a message header */
694 vector = talloc_array(mem_ctx, struct iovec, 1);
695 if (!vector) {
696 return -1;
698 ZERO_STRUCT(state->hdr);
699 vector[0].iov_base = (char *) state->hdr;
700 vector[0].iov_len = sizeof(state->hdr);
702 count = 1;
704 state->wait_for_hdr = true;
706 *_vector = vector;
707 *_count = count;
708 return 0;
711 /* and now fill the callers buffers and maybe the pending buffer */
712 state->wait_for_hdr = false;
714 msg_len = SVAL(state->hdr, 0);
716 if (msg_len == 0) {
717 errno = EIO;
718 return -1;
721 state->wait_for_hdr = false;
723 /* +1 because we may need to fill the pending buffer */
724 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
725 if (!vector) {
726 return -1;
729 count = 0;
730 left = msg_len;
731 while (left > 0 && state->count > 0) {
732 if (left < state->vector[0].iov_len) {
733 uint8_t *base;
734 base = (uint8_t *)state->vector[0].iov_base;
735 vector[count].iov_base = (char *) base;
736 vector[count].iov_len = left;
737 count++;
738 base += left;
739 state->vector[0].iov_base = (char *) base;
740 state->vector[0].iov_len -= left;
741 break;
743 vector[count] = state->vector[0];
744 count++;
745 left -= state->vector[0].iov_len;
746 state->vector += 1;
747 state->count -= 1;
750 if (left > 0) {
752 * if the message is longer than the buffers the caller
753 * requested, we need to consume the rest of the message
754 * into the pending buffer, where the next readv can
755 * be served from.
757 npas->pending.iov_base = talloc_array(npas, char, left);
758 if (!npas->pending.iov_base) {
759 return -1;
761 npas->pending.iov_len = left;
763 vector[count] = npas->pending;
764 count++;
767 state->ret += (msg_len - left);
769 *_vector = vector;
770 *_count = count;
771 return 0;
774 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
776 struct tevent_req *req = tevent_req_callback_data(subreq,
777 struct tevent_req);
778 int ret;
779 int sys_errno;
781 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
782 TALLOC_FREE(subreq);
783 if (ret == -1) {
784 tevent_req_error(req, sys_errno);
785 return;
789 * we do not set state->ret here as ret includes the headr size.
790 * we set it in tstream_npa_readv_pdu_next_vector()
793 tevent_req_done(req);
796 static int tstream_npa_readv_recv(struct tevent_req *req,
797 int *perrno)
799 struct tstream_npa_readv_state *state = tevent_req_data(req,
800 struct tstream_npa_readv_state);
801 int ret;
803 ret = tsocket_simple_int_recv(req, perrno);
804 if (ret == 0) {
805 ret = state->ret;
808 tevent_req_received(req);
809 return ret;
812 struct tstream_npa_writev_state {
813 const struct iovec *vector;
814 size_t count;
816 /* the header for message mode */
817 bool hdr_used;
818 uint8_t hdr[2];
820 int ret;
823 static void tstream_npa_writev_handler(struct tevent_req *subreq);
825 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
826 struct tevent_context *ev,
827 struct tstream_context *stream,
828 const struct iovec *vector,
829 size_t count)
831 struct tevent_req *req;
832 struct tstream_npa_writev_state *state;
833 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
834 struct tevent_req *subreq;
835 size_t msg_len;
836 size_t i;
837 struct iovec *new_vector;
839 req = tevent_req_create(mem_ctx, &state,
840 struct tstream_npa_writev_state);
841 if (!req) {
842 return NULL;
845 state->ret = 0;
847 if (!npas->unix_stream) {
848 tevent_req_error(req, ENOTCONN);
849 goto post;
852 switch (npas->file_type) {
853 case FILE_TYPE_BYTE_MODE_PIPE:
854 state->hdr_used = false;
855 state->vector = vector;
856 state->count = count;
857 break;
859 case FILE_TYPE_MESSAGE_MODE_PIPE:
861 * we make a copy of the vector and prepend a header
862 * with the length
864 new_vector = talloc_array(state, struct iovec, count + 1);
865 if (tevent_req_nomem(new_vector, req)) {
866 goto post;
868 new_vector[0].iov_base = (char *) state->hdr;
869 new_vector[0].iov_len = sizeof(state->hdr);
870 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
872 state->hdr_used = true;
873 state->vector = new_vector;
874 state->count = count + 1;
876 msg_len = 0;
877 for (i=0; i < count; i++) {
878 msg_len += vector[i].iov_len;
881 if (msg_len > UINT16_MAX) {
882 tevent_req_error(req, EMSGSIZE);
883 goto post;
886 SSVAL(state->hdr, 0, msg_len);
887 break;
890 subreq = tstream_writev_send(state,
892 npas->unix_stream,
893 state->vector,
894 state->count);
895 if (tevent_req_nomem(subreq, req)) {
896 goto post;
898 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
900 return req;
902 post:
903 tevent_req_post(req, ev);
904 return req;
907 static void tstream_npa_writev_handler(struct tevent_req *subreq)
909 struct tevent_req *req = tevent_req_callback_data(subreq,
910 struct tevent_req);
911 struct tstream_npa_writev_state *state = tevent_req_data(req,
912 struct tstream_npa_writev_state);
913 int ret;
914 int sys_errno;
916 ret = tstream_writev_recv(subreq, &sys_errno);
917 TALLOC_FREE(subreq);
918 if (ret == -1) {
919 tevent_req_error(req, sys_errno);
920 return;
924 * in message mode we need to hide the length
925 * of the hdr from the caller
927 if (state->hdr_used) {
928 ret -= sizeof(state->hdr);
931 state->ret = ret;
933 tevent_req_done(req);
936 static int tstream_npa_writev_recv(struct tevent_req *req,
937 int *perrno)
939 struct tstream_npa_writev_state *state = tevent_req_data(req,
940 struct tstream_npa_writev_state);
941 int ret;
943 ret = tsocket_simple_int_recv(req, perrno);
944 if (ret == 0) {
945 ret = state->ret;
948 tevent_req_received(req);
949 return ret;
952 struct tstream_npa_disconnect_state {
953 struct tstream_context *stream;
956 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
958 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
959 struct tevent_context *ev,
960 struct tstream_context *stream)
962 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
963 struct tevent_req *req;
964 struct tstream_npa_disconnect_state *state;
965 struct tevent_req *subreq;
967 req = tevent_req_create(mem_ctx, &state,
968 struct tstream_npa_disconnect_state);
969 if (req == NULL) {
970 return NULL;
973 state->stream = stream;
975 if (!npas->unix_stream) {
976 tevent_req_error(req, ENOTCONN);
977 goto post;
980 subreq = tstream_disconnect_send(state,
982 npas->unix_stream);
983 if (tevent_req_nomem(subreq, req)) {
984 goto post;
986 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
988 return req;
990 post:
991 tevent_req_post(req, ev);
992 return req;
995 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
997 struct tevent_req *req = tevent_req_callback_data(subreq,
998 struct tevent_req);
999 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
1000 struct tstream_npa_disconnect_state);
1001 struct tstream_context *stream = state->stream;
1002 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
1003 int ret;
1004 int sys_errno;
1006 ret = tstream_disconnect_recv(subreq, &sys_errno);
1007 TALLOC_FREE(subreq);
1008 if (ret == -1) {
1009 tevent_req_error(req, sys_errno);
1010 return;
1013 TALLOC_FREE(npas->unix_stream);
1015 tevent_req_done(req);
1018 static int tstream_npa_disconnect_recv(struct tevent_req *req,
1019 int *perrno)
1021 int ret;
1023 ret = tsocket_simple_int_recv(req, perrno);
1025 tevent_req_received(req);
1026 return ret;
1029 static const struct tstream_context_ops tstream_npa_ops = {
1030 .name = "npa",
1032 .pending_bytes = tstream_npa_pending_bytes,
1034 .readv_send = tstream_npa_readv_send,
1035 .readv_recv = tstream_npa_readv_recv,
1037 .writev_send = tstream_npa_writev_send,
1038 .writev_recv = tstream_npa_writev_recv,
1040 .disconnect_send = tstream_npa_disconnect_send,
1041 .disconnect_recv = tstream_npa_disconnect_recv,
1044 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1045 int fd,
1046 uint16_t file_type,
1047 struct tstream_context **_stream,
1048 const char *location)
1050 struct tstream_context *stream;
1051 struct tstream_npa *npas;
1052 int ret;
1054 switch (file_type) {
1055 case FILE_TYPE_BYTE_MODE_PIPE:
1056 break;
1057 case FILE_TYPE_MESSAGE_MODE_PIPE:
1058 break;
1059 default:
1060 errno = EINVAL;
1061 return -1;
1064 stream = tstream_context_create(mem_ctx,
1065 &tstream_npa_ops,
1066 &npas,
1067 struct tstream_npa,
1068 location);
1069 if (!stream) {
1070 return -1;
1072 ZERO_STRUCTP(npas);
1074 npas->file_type = file_type;
1076 ret = tstream_bsd_existing_socket(stream, fd,
1077 &npas->unix_stream);
1078 if (ret == -1) {
1079 int saved_errno = errno;
1080 talloc_free(stream);
1081 errno = saved_errno;
1082 return -1;
1085 *_stream = stream;
1086 return 0;
1090 struct tstream_npa_accept_state {
1091 struct tevent_context *ev;
1092 struct tstream_context *plain;
1093 uint16_t file_type;
1094 uint16_t device_state;
1095 uint64_t alloc_size;
1097 DATA_BLOB npa_blob;
1098 struct iovec out_iov;
1100 /* results */
1101 NTSTATUS accept_status;
1102 struct tsocket_address *client;
1103 char *client_name;
1104 struct tsocket_address *server;
1105 char *server_name;
1106 struct netr_SamInfo3 *info3;
1107 DATA_BLOB session_key;
1108 DATA_BLOB delegated_creds;
1111 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1112 void *private_data,
1113 TALLOC_CTX *mem_ctx,
1114 struct iovec **_vector,
1115 size_t *_count);
1116 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1117 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1119 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1120 struct tevent_context *ev,
1121 struct tstream_context *plain,
1122 uint16_t file_type,
1123 uint16_t device_state,
1124 uint64_t allocation_size)
1126 struct tstream_npa_accept_state *state;
1127 struct tevent_req *req, *subreq;
1129 req = tevent_req_create(mem_ctx, &state,
1130 struct tstream_npa_accept_state);
1131 if (req == NULL) {
1132 return NULL;
1135 switch (file_type) {
1136 case FILE_TYPE_BYTE_MODE_PIPE:
1137 break;
1138 case FILE_TYPE_MESSAGE_MODE_PIPE:
1139 break;
1140 default:
1141 tevent_req_error(req, EINVAL);
1142 goto post;
1145 ZERO_STRUCTP(state);
1147 state->ev = ev;
1148 state->plain = plain;
1149 state->file_type = file_type;
1150 state->device_state = device_state;
1151 state->alloc_size = allocation_size;
1154 * The named pipe pdu's have the length as 8 byte (initial_read_size),
1155 * named_pipe_full_request provides the pdu length then.
1157 subreq = tstream_readv_pdu_send(state, ev, plain,
1158 tstream_npa_accept_next_vector,
1159 state);
1160 if (tevent_req_nomem(subreq, req)) {
1161 goto post;
1164 tevent_req_set_callback(subreq,
1165 tstream_npa_accept_existing_reply, req);
1167 return req;
1169 post:
1170 tevent_req_post(req, ev);
1171 return req;
1174 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1175 void *private_data,
1176 TALLOC_CTX *mem_ctx,
1177 struct iovec **_vector,
1178 size_t *_count)
1180 struct tstream_npa_accept_state *state =
1181 talloc_get_type_abort(private_data,
1182 struct tstream_npa_accept_state);
1183 struct iovec *vector;
1184 size_t count;
1185 off_t ofs = 0;
1187 if (state->npa_blob.length == 0) {
1188 state->npa_blob = data_blob_talloc(state, NULL, 4);
1189 if (!state->npa_blob.data) {
1190 return -1;
1192 } else if (state->npa_blob.length == 4) {
1193 uint32_t msg_len;
1195 ofs = 4;
1197 msg_len = RIVAL(state->npa_blob.data, 0);
1199 if (msg_len > 0x00FFFFFF) {
1200 errno = EMSGSIZE;
1201 return -1;
1204 if (msg_len == 0) {
1205 errno = EMSGSIZE;
1206 return -1;
1209 msg_len += ofs;
1211 state->npa_blob.data = talloc_realloc(state,
1212 state->npa_blob.data,
1213 uint8_t, msg_len);
1214 if (!state->npa_blob.data) {
1215 return -1;
1217 state->npa_blob.length = msg_len;
1218 } else {
1219 if (memcmp(&state->npa_blob.data[4],
1220 NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1221 DEBUG(0, ("Wrong protocol\n"));
1222 #if defined(EPROTONOSUPPORT)
1223 errno = EPROTONOSUPPORT;
1224 #elif defined(EPROTO)
1225 errno = EPROTO;
1226 #else
1227 errno = EINVAL;
1228 #endif
1229 return -1;
1231 *_vector = NULL;
1232 *_count = 0;
1233 return 0;
1236 /* we need to get a message header */
1237 vector = talloc_array(mem_ctx, struct iovec, 1);
1238 if (!vector) {
1239 return -1;
1241 vector[0].iov_base = (char *) (state->npa_blob.data + ofs);
1242 vector[0].iov_len = state->npa_blob.length - ofs;
1243 count = 1;
1245 *_vector = vector;
1246 *_count = count;
1247 return 0;
1250 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1252 struct tevent_req *req =
1253 tevent_req_callback_data(subreq, struct tevent_req);
1254 struct tstream_npa_accept_state *state =
1255 tevent_req_data(req, struct tstream_npa_accept_state);
1256 struct named_pipe_auth_req *pipe_request;
1257 struct named_pipe_auth_rep pipe_reply;
1258 struct named_pipe_auth_req_info3 i3;
1259 enum ndr_err_code ndr_err;
1260 DATA_BLOB out;
1261 int sys_errno;
1262 int ret;
1264 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1265 TALLOC_FREE(subreq);
1266 if (ret == -1) {
1267 tevent_req_error(req, sys_errno);
1268 return;
1271 DEBUG(10, ("Received packet of length %lu\n",
1272 (long)state->npa_blob.length));
1273 dump_data(11, state->npa_blob.data, state->npa_blob.length);
1275 ZERO_STRUCT(pipe_reply);
1276 pipe_reply.level = 0;
1277 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1279 * TODO: check it's a root (uid == 0) pipe
1282 pipe_request = talloc(state, struct named_pipe_auth_req);
1283 if (!pipe_request) {
1284 DEBUG(0, ("Out of memory!\n"));
1285 goto reply;
1288 /* parse the passed credentials */
1289 ndr_err = ndr_pull_struct_blob_all(
1290 &state->npa_blob, pipe_request, pipe_request,
1291 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1294 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1295 nt_errstr(pipe_reply.status)));
1296 goto reply;
1299 if (DEBUGLVL(10)) {
1300 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1303 ZERO_STRUCT(i3);
1305 switch (pipe_request->level) {
1306 case 0:
1307 pipe_reply.level = 0;
1308 pipe_reply.status = NT_STATUS_OK;
1310 /* we need to force byte mode in this level */
1311 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1312 break;
1314 case 1:
1315 pipe_reply.level = 1;
1316 pipe_reply.status = NT_STATUS_OK;
1318 /* We must copy net3_SamInfo3, so that
1319 * info3 is an actual talloc pointer, then we steal
1320 * pipe_request on info3 so that all the allocated memory
1321 * pointed by the structrue members is preserved */
1322 state->info3 = (struct netr_SamInfo3 *)talloc_memdup(state,
1323 &pipe_request->info.info1,
1324 sizeof(struct netr_SamInfo3));
1325 if (!state->info3) {
1326 pipe_reply.status = NT_STATUS_NO_MEMORY;
1327 DEBUG(0, ("Out of memory!\n"));
1328 goto reply;
1330 talloc_steal(state->info3, pipe_request);
1332 /* we need to force byte mode in this level */
1333 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1334 break;
1336 case 2:
1337 pipe_reply.level = 2;
1338 pipe_reply.status = NT_STATUS_OK;
1339 pipe_reply.info.info2.file_type = state->file_type;
1340 pipe_reply.info.info2.device_state = state->device_state;
1341 pipe_reply.info.info2.allocation_size = state->alloc_size;
1343 i3.client_name = pipe_request->info.info2.client_name;
1344 i3.client_addr = pipe_request->info.info2.client_addr;
1345 i3.client_port = pipe_request->info.info2.client_port;
1346 i3.server_name = pipe_request->info.info2.server_name;
1347 i3.server_addr = pipe_request->info.info2.server_addr;
1348 i3.server_port = pipe_request->info.info2.server_port;
1349 i3.sam_info3 = pipe_request->info.info2.sam_info3;
1350 i3.session_key_length =
1351 pipe_request->info.info2.session_key_length;
1352 i3.session_key = pipe_request->info.info2.session_key;
1353 break;
1355 case 3:
1356 pipe_reply.level = 3;
1357 pipe_reply.status = NT_STATUS_OK;
1358 pipe_reply.info.info3.file_type = state->file_type;
1359 pipe_reply.info.info3.device_state = state->device_state;
1360 pipe_reply.info.info3.allocation_size = state->alloc_size;
1362 i3 = pipe_request->info.info3;
1363 break;
1365 default:
1366 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1367 pipe_reply.level = 0;
1368 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1369 goto reply;
1372 if (pipe_reply.level >=2) {
1374 if (i3.server_addr == NULL) {
1375 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1376 DEBUG(2, ("Missing server address\n"));
1377 goto reply;
1379 if (i3.client_addr == NULL) {
1380 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1381 DEBUG(2, ("Missing client address\n"));
1382 goto reply;
1385 state->server_name = discard_const_p(char,
1386 talloc_move(state, &i3.server_name));
1387 ret = tsocket_address_inet_from_strings(state, "ip",
1388 i3.server_addr,
1389 i3.server_port,
1390 &state->server);
1391 if (ret != 0) {
1392 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1393 i3.server_addr, i3.server_port,
1394 strerror(errno)));
1395 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1396 goto reply;
1399 state->client_name = discard_const_p(char,
1400 talloc_move(state, &i3.client_name));
1401 ret = tsocket_address_inet_from_strings(state, "ip",
1402 i3.client_addr,
1403 i3.client_port,
1404 &state->client);
1405 if (ret != 0) {
1406 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1407 i3.client_addr, i3.client_port,
1408 strerror(errno)));
1409 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1410 goto reply;
1413 state->info3 = talloc_move(state, &i3.sam_info3);
1414 state->session_key.data = talloc_move(state, &i3.session_key);
1415 state->session_key.length = i3.session_key_length;
1418 if (pipe_reply.level >= 3) {
1419 state->delegated_creds.data =
1420 talloc_move(state, &i3.gssapi_delegated_creds);
1421 state->delegated_creds.length =
1422 i3.gssapi_delegated_creds_length;
1425 reply:
1426 /* create the output */
1427 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1428 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1429 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1430 DEBUG(2, ("Error encoding structure: %s",
1431 ndr_map_error2string(ndr_err)));
1432 tevent_req_error(req, EIO);
1433 return;
1436 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1437 dump_data(11, out.data, out.length);
1439 if (DEBUGLVL(10)) {
1440 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1443 state->accept_status = pipe_reply.status;
1445 state->out_iov.iov_base = (char *) out.data;
1446 state->out_iov.iov_len = out.length;
1448 subreq = tstream_writev_send(state, state->ev,
1449 state->plain,
1450 &state->out_iov, 1);
1451 if (tevent_req_nomem(subreq, req)) {
1452 DEBUG(0, ("no memory for tstream_writev_send"));
1453 return;
1456 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1459 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1461 struct tevent_req *req =
1462 tevent_req_callback_data(subreq, struct tevent_req);
1463 int sys_errno;
1464 int ret;
1466 ret = tstream_writev_recv(subreq, &sys_errno);
1467 TALLOC_FREE(subreq);
1468 if (ret == -1) {
1469 tevent_req_error(req, sys_errno);
1470 return;
1473 tevent_req_done(req);
1476 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1477 int *perrno,
1478 TALLOC_CTX *mem_ctx,
1479 struct tstream_context **stream,
1480 struct tsocket_address **client,
1481 char **_client_name,
1482 struct tsocket_address **server,
1483 char **server_name,
1484 struct netr_SamInfo3 **info3,
1485 DATA_BLOB *session_key,
1486 DATA_BLOB *delegated_creds,
1487 const char *location)
1489 struct tstream_npa_accept_state *state =
1490 tevent_req_data(req, struct tstream_npa_accept_state);
1491 struct tstream_npa *npas;
1492 int ret;
1494 ret = tsocket_simple_int_recv(req, perrno);
1495 if (ret != 0) {
1496 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1497 strerror(*perrno)));
1498 tevent_req_received(req);
1499 return -1;
1502 if (!NT_STATUS_IS_OK(state->accept_status)) {
1503 #if defined(EPROTONOSUPPORT)
1504 *perrno = EPROTONOSUPPORT;
1505 #elif defined(EPROTO)
1506 *perrno = EPROTO;
1507 #else
1508 *perrno = EINVAL;
1509 #endif
1510 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1511 nt_errstr(state->accept_status),
1512 strerror(*perrno)));
1513 tevent_req_received(req);
1514 return -1;
1517 *stream = tstream_context_create(mem_ctx,
1518 &tstream_npa_ops,
1519 &npas,
1520 struct tstream_npa,
1521 location);
1522 if (!*stream) {
1523 *perrno = ENOMEM;
1524 tevent_req_received(req);
1525 return -1;
1527 ZERO_STRUCTP(npas);
1528 npas->unix_stream = state->plain;
1529 npas->file_type = state->file_type;
1531 *client = talloc_move(mem_ctx, &state->client);
1532 *_client_name = talloc_move(mem_ctx, &state->client_name);
1533 *server = talloc_move(mem_ctx, &state->server);
1534 *server_name = talloc_move(mem_ctx, &state->server_name);
1535 *info3 = talloc_move(mem_ctx, &state->info3);
1536 *session_key = state->session_key;
1537 talloc_steal(mem_ctx, state->session_key.data);
1538 *delegated_creds = state->delegated_creds;
1539 talloc_steal(mem_ctx, state->delegated_creds.data);
1541 tevent_req_received(req);
1542 return 0;