s4:drsuapi RPC server - fix "enum security_user_level" warning on Tru64
[Samba/gebeck_regimport.git] / libcli / named_pipe_auth / npa_tstream.c
blob1f29a90e29ce27d3f78611daefe5df7af9918854
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 #if _SAMBA_BUILD_ == 4
28 #include "libcli/raw/smb.h"
29 #endif
31 static const struct tstream_context_ops tstream_npa_ops;
33 struct tstream_npa {
34 struct tstream_context *unix_stream;
36 uint16_t file_type;
38 struct iovec pending;
41 struct tstream_npa_connect_state {
42 struct {
43 struct tevent_context *ev;
44 } caller;
46 const char *unix_path;
47 struct tsocket_address *unix_laddr;
48 struct tsocket_address *unix_raddr;
49 struct tstream_context *unix_stream;
51 struct named_pipe_auth_req auth_req;
52 DATA_BLOB auth_req_blob;
53 struct iovec auth_req_iov;
55 struct named_pipe_auth_rep auth_rep;
56 DATA_BLOB auth_rep_blob;
59 static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
61 struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
62 struct tevent_context *ev,
63 const char *directory,
64 const char *npipe,
65 const struct tsocket_address *client,
66 const char *client_name_in,
67 const struct tsocket_address *server,
68 const char *server_name,
69 const struct netr_SamInfo3 *sam_info3,
70 DATA_BLOB session_key,
71 DATA_BLOB delegated_creds)
73 struct tevent_req *req;
74 struct tstream_npa_connect_state *state;
75 struct tevent_req *subreq;
76 int ret;
77 enum ndr_err_code ndr_err;
78 char *lower_case_npipe;
80 req = tevent_req_create(mem_ctx, &state,
81 struct tstream_npa_connect_state);
82 if (!req) {
83 return NULL;
86 state->caller.ev = ev;
88 lower_case_npipe = strlower_talloc(state, npipe);
89 if (tevent_req_nomem(lower_case_npipe, req)) {
90 goto post;
93 state->unix_path = talloc_asprintf(state, "%s/%s",
94 directory,
95 lower_case_npipe);
96 talloc_free(lower_case_npipe);
97 if (tevent_req_nomem(state->unix_path, req)) {
98 goto post;
101 ret = tsocket_address_unix_from_path(state,
103 &state->unix_laddr);
104 if (ret == -1) {
105 tevent_req_error(req, errno);
106 goto post;
109 ret = tsocket_address_unix_from_path(state,
110 state->unix_path,
111 &state->unix_raddr);
112 if (ret == -1) {
113 tevent_req_error(req, errno);
114 goto post;
117 ZERO_STRUCT(state->auth_req);
118 if (client) {
119 struct named_pipe_auth_req_info3 *info3;
121 if (!server) {
122 tevent_req_error(req, EINVAL);
123 goto post;
126 state->auth_req.level = 3;
127 info3 = &state->auth_req.info.info3;
129 info3->client_name = client_name_in;
130 info3->client_addr = tsocket_address_inet_addr_string(client, state);
131 if (!info3->client_addr) {
132 /* errno might be EINVAL */
133 tevent_req_error(req, errno);
134 goto post;
136 info3->client_port = tsocket_address_inet_port(client);
137 if (!info3->client_name) {
138 info3->client_name = info3->client_addr;
141 info3->server_addr = tsocket_address_inet_addr_string(server, state);
142 if (!info3->server_addr) {
143 /* errno might be EINVAL */
144 tevent_req_error(req, errno);
145 goto post;
147 info3->server_port = tsocket_address_inet_port(server);
148 if (!info3->server_name) {
149 info3->server_name = info3->server_addr;
152 info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3);
153 info3->session_key_length = session_key.length;
154 info3->session_key = session_key.data;
155 info3->gssapi_delegated_creds_length = delegated_creds.length;
156 info3->gssapi_delegated_creds = delegated_creds.data;
158 } else if (sam_info3) {
159 state->auth_req.level = 1;
160 state->auth_req.info.info1 = *sam_info3;
161 } else {
162 state->auth_req.level = 0;
165 if (DEBUGLVL(10)) {
166 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
169 ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
170 state, &state->auth_req,
171 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
172 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
173 tevent_req_error(req, EINVAL);
174 goto post;
177 state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
178 state->auth_req_iov.iov_len = state->auth_req_blob.length;
180 subreq = tstream_unix_connect_send(state,
181 state->caller.ev,
182 state->unix_laddr,
183 state->unix_raddr);
184 if (tevent_req_nomem(subreq, req)) {
185 goto post;
187 tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
189 return req;
191 post:
192 tevent_req_post(req, ev);
193 return req;
196 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
198 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
200 struct tevent_req *req =
201 tevent_req_callback_data(subreq,
202 struct tevent_req);
203 struct tstream_npa_connect_state *state =
204 tevent_req_data(req,
205 struct tstream_npa_connect_state);
206 int ret;
207 int sys_errno;
209 ret = tstream_unix_connect_recv(subreq, &sys_errno,
210 state, &state->unix_stream);
211 TALLOC_FREE(subreq);
212 if (ret == -1) {
213 tevent_req_error(req, sys_errno);
214 return;
217 subreq = tstream_writev_send(state,
218 state->caller.ev,
219 state->unix_stream,
220 &state->auth_req_iov, 1);
221 if (tevent_req_nomem(subreq, req)) {
222 return;
224 tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
227 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
228 void *private_data,
229 TALLOC_CTX *mem_ctx,
230 struct iovec **_vector,
231 size_t *_count);
232 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
234 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
236 struct tevent_req *req =
237 tevent_req_callback_data(subreq,
238 struct tevent_req);
239 struct tstream_npa_connect_state *state =
240 tevent_req_data(req,
241 struct tstream_npa_connect_state);
242 int ret;
243 int sys_errno;
245 ret = tstream_writev_recv(subreq, &sys_errno);
246 TALLOC_FREE(subreq);
247 if (ret == -1) {
248 tevent_req_error(req, sys_errno);
249 return;
252 state->auth_rep_blob = data_blob_const(NULL, 0);
254 subreq = tstream_readv_pdu_send(state, state->caller.ev,
255 state->unix_stream,
256 tstream_npa_connect_next_vector,
257 state);
258 if (tevent_req_nomem(subreq, req)) {
259 return;
261 tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
264 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
265 void *private_data,
266 TALLOC_CTX *mem_ctx,
267 struct iovec **_vector,
268 size_t *_count)
270 struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
271 struct tstream_npa_connect_state);
272 struct iovec *vector;
273 size_t count;
274 off_t ofs = 0;
276 if (state->auth_rep_blob.length == 0) {
277 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
278 if (!state->auth_rep_blob.data) {
279 return -1;
281 } else if (state->auth_rep_blob.length == 4) {
282 uint32_t msg_len;
284 ofs = 4;
286 msg_len = RIVAL(state->auth_rep_blob.data, 0);
288 if (msg_len > 0x00FFFFFF) {
289 errno = EMSGSIZE;
290 return -1;
293 if (msg_len == 0) {
294 errno = EMSGSIZE;
295 return -1;
298 msg_len += ofs;
300 state->auth_rep_blob.data = talloc_realloc(state,
301 state->auth_rep_blob.data,
302 uint8_t, msg_len);
303 if (!state->auth_rep_blob.data) {
304 return -1;
306 state->auth_rep_blob.length = msg_len;
307 } else {
308 *_vector = NULL;
309 *_count = 0;
310 return 0;
313 /* we need to get a message header */
314 vector = talloc_array(mem_ctx, struct iovec, 1);
315 if (!vector) {
316 return -1;
318 vector[0].iov_base = (char *) (state->auth_rep_blob.data + ofs);
319 vector[0].iov_len = state->auth_rep_blob.length - ofs;
320 count = 1;
322 *_vector = vector;
323 *_count = count;
324 return 0;
327 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
329 struct tevent_req *req =
330 tevent_req_callback_data(subreq,
331 struct tevent_req);
332 struct tstream_npa_connect_state *state =
333 tevent_req_data(req,
334 struct tstream_npa_connect_state);
335 int ret;
336 int sys_errno;
337 enum ndr_err_code ndr_err;
339 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
340 TALLOC_FREE(subreq);
341 if (ret == -1) {
342 tevent_req_error(req, sys_errno);
343 return;
346 DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
347 (uint32_t)state->auth_rep_blob.length));
348 dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
350 ndr_err = ndr_pull_struct_blob(
351 &state->auth_rep_blob, state,
352 &state->auth_rep,
353 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
355 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
356 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
357 ndr_map_error2string(ndr_err)));
358 tevent_req_error(req, EIO);
359 return;
362 if (DEBUGLVL(10)) {
363 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
366 if (state->auth_rep.length < 16) {
367 DEBUG(0, ("req invalid length: %u < 16\n",
368 state->auth_rep.length));
369 tevent_req_error(req, EIO);
370 return;
373 if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
374 DEBUG(0, ("req invalid magic: %s != %s\n",
375 state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
376 tevent_req_error(req, EIO);
377 return;
380 if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
381 DEBUG(0, ("req failed: %s\n",
382 nt_errstr(state->auth_rep.status)));
383 tevent_req_error(req, EACCES);
384 return;
387 if (state->auth_rep.level != state->auth_req.level) {
388 DEBUG(0, ("req invalid level: %u != %u\n",
389 state->auth_rep.level, state->auth_req.level));
390 tevent_req_error(req, EIO);
391 return;
394 tevent_req_done(req);
397 int _tstream_npa_connect_recv(struct tevent_req *req,
398 int *perrno,
399 TALLOC_CTX *mem_ctx,
400 struct tstream_context **_stream,
401 uint16_t *_file_type,
402 uint16_t *_device_state,
403 uint64_t *_allocation_size,
404 const char *location)
406 struct tstream_npa_connect_state *state =
407 tevent_req_data(req,
408 struct tstream_npa_connect_state);
409 struct tstream_context *stream;
410 struct tstream_npa *npas;
411 uint16_t device_state = 0;
412 uint64_t allocation_size = 0;
414 if (tevent_req_is_unix_error(req, perrno)) {
415 tevent_req_received(req);
416 return -1;
419 stream = tstream_context_create(mem_ctx,
420 &tstream_npa_ops,
421 &npas,
422 struct tstream_npa,
423 location);
424 if (!stream) {
425 *perrno = ENOMEM;
426 tevent_req_received(req);
427 return -1;
429 ZERO_STRUCTP(npas);
431 npas->unix_stream = talloc_move(stream, &state->unix_stream);
432 switch (state->auth_rep.level) {
433 case 0:
434 case 1:
435 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
436 device_state = 0x00ff;
437 allocation_size = 2048;
438 break;
439 case 2:
440 npas->file_type = state->auth_rep.info.info2.file_type;
441 device_state = state->auth_rep.info.info2.device_state;
442 allocation_size = state->auth_rep.info.info2.allocation_size;
443 break;
444 case 3:
445 npas->file_type = state->auth_rep.info.info3.file_type;
446 device_state = state->auth_rep.info.info3.device_state;
447 allocation_size = state->auth_rep.info.info3.allocation_size;
448 break;
451 *_stream = stream;
452 *_file_type = npas->file_type;
453 *_device_state = device_state;
454 *_allocation_size = allocation_size;
455 tevent_req_received(req);
456 return 0;
459 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
461 struct tstream_npa *npas = tstream_context_data(stream,
462 struct tstream_npa);
463 ssize_t ret;
465 if (!npas->unix_stream) {
466 errno = ENOTCONN;
467 return -1;
470 switch (npas->file_type) {
471 case FILE_TYPE_BYTE_MODE_PIPE:
472 ret = tstream_pending_bytes(npas->unix_stream);
473 break;
475 case FILE_TYPE_MESSAGE_MODE_PIPE:
476 ret = npas->pending.iov_len;
477 break;
479 default:
480 ret = -1;
483 return ret;
486 struct tstream_npa_readv_state {
487 struct tstream_context *stream;
489 struct iovec *vector;
490 size_t count;
492 /* the header for message mode */
493 uint8_t hdr[2];
494 bool wait_for_hdr;
496 int ret;
499 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
500 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
501 void *private_data,
502 TALLOC_CTX *mem_ctx,
503 struct iovec **_vector,
504 size_t *_count);
505 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
507 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
508 struct tevent_context *ev,
509 struct tstream_context *stream,
510 struct iovec *vector,
511 size_t count)
513 struct tevent_req *req;
514 struct tstream_npa_readv_state *state;
515 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
516 struct tevent_req *subreq;
517 off_t ofs;
518 size_t left;
519 uint8_t *pbase;
521 req = tevent_req_create(mem_ctx, &state,
522 struct tstream_npa_readv_state);
523 if (!req) {
524 return NULL;
527 state->stream = stream;
528 state->ret = 0;
530 if (!npas->unix_stream) {
531 tevent_req_error(req, ENOTCONN);
532 goto post;
535 switch (npas->file_type) {
536 case FILE_TYPE_BYTE_MODE_PIPE:
537 state->vector = vector;
538 state->count = count;
540 subreq = tstream_readv_send(state,
542 npas->unix_stream,
543 state->vector,
544 state->count);
545 if (tevent_req_nomem(subreq,req)) {
546 goto post;
548 tevent_req_set_callback(subreq,
549 tstream_npa_readv_byte_mode_handler,
550 req);
552 return req;
554 case FILE_TYPE_MESSAGE_MODE_PIPE:
556 * we make a copy of the vector and prepend a header
557 * with the length
559 state->vector = talloc_array(state, struct iovec, count);
560 if (tevent_req_nomem(state->vector, req)) {
561 goto post;
563 memcpy(state->vector, vector, sizeof(struct iovec)*count);
564 state->count = count;
567 * copy the pending buffer first
569 ofs = 0;
570 left = npas->pending.iov_len;
571 pbase = (uint8_t *)npas->pending.iov_base;
573 while (left > 0 && state->count > 0) {
574 uint8_t *base;
575 base = (uint8_t *)state->vector[0].iov_base;
576 if (left < state->vector[0].iov_len) {
577 memcpy(base, pbase + ofs, left);
579 base += left;
580 state->vector[0].iov_base = (char *) base;
581 state->vector[0].iov_len -= left;
583 ofs += left;
584 left = 0;
585 TALLOC_FREE(pbase);
586 ZERO_STRUCT(npas->pending);
587 break;
589 memcpy(base, pbase + ofs, state->vector[0].iov_len);
591 ofs += state->vector[0].iov_len;
592 left -= state->vector[0].iov_len;
593 state->vector += 1;
594 state->count -= 1;
596 if (left == 0) {
597 TALLOC_FREE(pbase);
598 ZERO_STRUCT(npas->pending);
599 break;
603 if (left > 0) {
604 memmove(pbase, pbase + ofs, left);
605 npas->pending.iov_base = (char *) pbase;
606 npas->pending.iov_len = left;
608 * this cannot fail and even if it
609 * fails we can handle it
611 pbase = talloc_realloc(npas, pbase, uint8_t, left);
612 if (pbase) {
613 npas->pending.iov_base = (char *) pbase;
615 pbase = NULL;
618 state->ret += ofs;
620 if (state->count == 0) {
621 tevent_req_done(req);
622 goto post;
625 ZERO_STRUCT(state->hdr);
626 state->wait_for_hdr = false;
628 subreq = tstream_readv_pdu_send(state,
630 npas->unix_stream,
631 tstream_npa_readv_next_vector,
632 state);
633 if (tevent_req_nomem(subreq, req)) {
634 goto post;
636 tevent_req_set_callback(subreq,
637 tstream_npa_readv_msg_mode_handler,
638 req);
640 return req;
643 /* this can't happen */
644 tevent_req_error(req, EINVAL);
645 goto post;
647 post:
648 tevent_req_post(req, ev);
649 return req;
652 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
654 struct tevent_req *req = tevent_req_callback_data(subreq,
655 struct tevent_req);
656 struct tstream_npa_readv_state *state = tevent_req_data(req,
657 struct tstream_npa_readv_state);
658 int ret;
659 int sys_errno;
661 ret = tstream_readv_recv(subreq, &sys_errno);
662 TALLOC_FREE(subreq);
663 if (ret == -1) {
664 tevent_req_error(req, sys_errno);
665 return;
668 state->ret = ret;
670 tevent_req_done(req);
673 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
674 void *private_data,
675 TALLOC_CTX *mem_ctx,
676 struct iovec **_vector,
677 size_t *_count)
679 struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
680 struct tstream_npa_readv_state);
681 struct tstream_npa *npas = tstream_context_data(state->stream,
682 struct tstream_npa);
683 struct iovec *vector;
684 size_t count;
685 uint16_t msg_len;
686 size_t left;
688 if (state->count == 0) {
689 *_vector = NULL;
690 *_count = 0;
691 return 0;
694 if (!state->wait_for_hdr) {
695 /* we need to get a message header */
696 vector = talloc_array(mem_ctx, struct iovec, 1);
697 if (!vector) {
698 return -1;
700 ZERO_STRUCT(state->hdr);
701 vector[0].iov_base = (char *) state->hdr;
702 vector[0].iov_len = sizeof(state->hdr);
704 count = 1;
706 state->wait_for_hdr = true;
708 *_vector = vector;
709 *_count = count;
710 return 0;
713 /* and now fill the callers buffers and maybe the pending buffer */
714 state->wait_for_hdr = false;
716 msg_len = SVAL(state->hdr, 0);
718 if (msg_len == 0) {
719 errno = EIO;
720 return -1;
723 state->wait_for_hdr = false;
725 /* +1 because we may need to fill the pending buffer */
726 vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
727 if (!vector) {
728 return -1;
731 count = 0;
732 left = msg_len;
733 while (left > 0 && state->count > 0) {
734 if (left < state->vector[0].iov_len) {
735 uint8_t *base;
736 base = (uint8_t *)state->vector[0].iov_base;
737 vector[count].iov_base = (char *) base;
738 vector[count].iov_len = left;
739 count++;
740 base += left;
741 state->vector[0].iov_base = (char *) base;
742 state->vector[0].iov_len -= left;
743 break;
745 vector[count] = state->vector[0];
746 count++;
747 left -= state->vector[0].iov_len;
748 state->vector += 1;
749 state->count -= 1;
752 if (left > 0) {
754 * if the message is longer than the buffers the caller
755 * requested, we need to consume the rest of the message
756 * into the pending buffer, where the next readv can
757 * be served from.
759 npas->pending.iov_base = talloc_array(npas, char, left);
760 if (!npas->pending.iov_base) {
761 return -1;
763 npas->pending.iov_len = left;
765 vector[count] = npas->pending;
766 count++;
769 state->ret += (msg_len - left);
771 *_vector = vector;
772 *_count = count;
773 return 0;
776 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
778 struct tevent_req *req = tevent_req_callback_data(subreq,
779 struct tevent_req);
780 int ret;
781 int sys_errno;
783 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
784 TALLOC_FREE(subreq);
785 if (ret == -1) {
786 tevent_req_error(req, sys_errno);
787 return;
791 * we do not set state->ret here as ret includes the headr size.
792 * we set it in tstream_npa_readv_pdu_next_vector()
795 tevent_req_done(req);
798 static int tstream_npa_readv_recv(struct tevent_req *req,
799 int *perrno)
801 struct tstream_npa_readv_state *state = tevent_req_data(req,
802 struct tstream_npa_readv_state);
803 int ret;
805 ret = tsocket_simple_int_recv(req, perrno);
806 if (ret == 0) {
807 ret = state->ret;
810 tevent_req_received(req);
811 return ret;
814 struct tstream_npa_writev_state {
815 const struct iovec *vector;
816 size_t count;
818 /* the header for message mode */
819 bool hdr_used;
820 uint8_t hdr[2];
822 int ret;
825 static void tstream_npa_writev_handler(struct tevent_req *subreq);
827 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
828 struct tevent_context *ev,
829 struct tstream_context *stream,
830 const struct iovec *vector,
831 size_t count)
833 struct tevent_req *req;
834 struct tstream_npa_writev_state *state;
835 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
836 struct tevent_req *subreq;
837 size_t msg_len;
838 size_t i;
839 struct iovec *new_vector;
841 req = tevent_req_create(mem_ctx, &state,
842 struct tstream_npa_writev_state);
843 if (!req) {
844 return NULL;
847 state->ret = 0;
849 if (!npas->unix_stream) {
850 tevent_req_error(req, ENOTCONN);
851 goto post;
854 switch (npas->file_type) {
855 case FILE_TYPE_BYTE_MODE_PIPE:
856 state->hdr_used = false;
857 state->vector = vector;
858 state->count = count;
859 break;
861 case FILE_TYPE_MESSAGE_MODE_PIPE:
863 * we make a copy of the vector and prepend a header
864 * with the length
866 new_vector = talloc_array(state, struct iovec, count + 1);
867 if (tevent_req_nomem(new_vector, req)) {
868 goto post;
870 new_vector[0].iov_base = (char *) state->hdr;
871 new_vector[0].iov_len = sizeof(state->hdr);
872 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
874 state->hdr_used = true;
875 state->vector = new_vector;
876 state->count = count + 1;
878 msg_len = 0;
879 for (i=0; i < count; i++) {
880 msg_len += vector[i].iov_len;
883 if (msg_len > UINT16_MAX) {
884 tevent_req_error(req, EMSGSIZE);
885 goto post;
888 SSVAL(state->hdr, 0, msg_len);
889 break;
892 subreq = tstream_writev_send(state,
894 npas->unix_stream,
895 state->vector,
896 state->count);
897 if (tevent_req_nomem(subreq, req)) {
898 goto post;
900 tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
902 return req;
904 post:
905 tevent_req_post(req, ev);
906 return req;
909 static void tstream_npa_writev_handler(struct tevent_req *subreq)
911 struct tevent_req *req = tevent_req_callback_data(subreq,
912 struct tevent_req);
913 struct tstream_npa_writev_state *state = tevent_req_data(req,
914 struct tstream_npa_writev_state);
915 int ret;
916 int sys_errno;
918 ret = tstream_writev_recv(subreq, &sys_errno);
919 TALLOC_FREE(subreq);
920 if (ret == -1) {
921 tevent_req_error(req, sys_errno);
922 return;
926 * in message mode we need to hide the length
927 * of the hdr from the caller
929 if (state->hdr_used) {
930 ret -= sizeof(state->hdr);
933 state->ret = ret;
935 tevent_req_done(req);
938 static int tstream_npa_writev_recv(struct tevent_req *req,
939 int *perrno)
941 struct tstream_npa_writev_state *state = tevent_req_data(req,
942 struct tstream_npa_writev_state);
943 int ret;
945 ret = tsocket_simple_int_recv(req, perrno);
946 if (ret == 0) {
947 ret = state->ret;
950 tevent_req_received(req);
951 return ret;
954 struct tstream_npa_disconnect_state {
955 struct tstream_context *stream;
958 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
960 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
961 struct tevent_context *ev,
962 struct tstream_context *stream)
964 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
965 struct tevent_req *req;
966 struct tstream_npa_disconnect_state *state;
967 struct tevent_req *subreq;
969 req = tevent_req_create(mem_ctx, &state,
970 struct tstream_npa_disconnect_state);
971 if (req == NULL) {
972 return NULL;
975 state->stream = stream;
977 if (!npas->unix_stream) {
978 tevent_req_error(req, ENOTCONN);
979 goto post;
982 subreq = tstream_disconnect_send(state,
984 npas->unix_stream);
985 if (tevent_req_nomem(subreq, req)) {
986 goto post;
988 tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
990 return req;
992 post:
993 tevent_req_post(req, ev);
994 return req;
997 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
999 struct tevent_req *req = tevent_req_callback_data(subreq,
1000 struct tevent_req);
1001 struct tstream_npa_disconnect_state *state = tevent_req_data(req,
1002 struct tstream_npa_disconnect_state);
1003 struct tstream_context *stream = state->stream;
1004 struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
1005 int ret;
1006 int sys_errno;
1008 ret = tstream_disconnect_recv(subreq, &sys_errno);
1009 TALLOC_FREE(subreq);
1010 if (ret == -1) {
1011 tevent_req_error(req, sys_errno);
1012 return;
1015 TALLOC_FREE(npas->unix_stream);
1017 tevent_req_done(req);
1020 static int tstream_npa_disconnect_recv(struct tevent_req *req,
1021 int *perrno)
1023 int ret;
1025 ret = tsocket_simple_int_recv(req, perrno);
1027 tevent_req_received(req);
1028 return ret;
1031 static const struct tstream_context_ops tstream_npa_ops = {
1032 .name = "npa",
1034 .pending_bytes = tstream_npa_pending_bytes,
1036 .readv_send = tstream_npa_readv_send,
1037 .readv_recv = tstream_npa_readv_recv,
1039 .writev_send = tstream_npa_writev_send,
1040 .writev_recv = tstream_npa_writev_recv,
1042 .disconnect_send = tstream_npa_disconnect_send,
1043 .disconnect_recv = tstream_npa_disconnect_recv,
1046 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1047 int fd,
1048 uint16_t file_type,
1049 struct tstream_context **_stream,
1050 const char *location)
1052 struct tstream_context *stream;
1053 struct tstream_npa *npas;
1054 int ret;
1056 switch (file_type) {
1057 case FILE_TYPE_BYTE_MODE_PIPE:
1058 break;
1059 case FILE_TYPE_MESSAGE_MODE_PIPE:
1060 break;
1061 default:
1062 errno = EINVAL;
1063 return -1;
1066 stream = tstream_context_create(mem_ctx,
1067 &tstream_npa_ops,
1068 &npas,
1069 struct tstream_npa,
1070 location);
1071 if (!stream) {
1072 return -1;
1074 ZERO_STRUCTP(npas);
1076 npas->file_type = file_type;
1078 ret = tstream_bsd_existing_socket(stream, fd,
1079 &npas->unix_stream);
1080 if (ret == -1) {
1081 int saved_errno = errno;
1082 talloc_free(stream);
1083 errno = saved_errno;
1084 return -1;
1087 *_stream = stream;
1088 return 0;
1092 struct tstream_npa_accept_state {
1093 struct tevent_context *ev;
1094 struct tstream_context *plain;
1095 uint16_t file_type;
1096 uint16_t device_state;
1097 uint64_t alloc_size;
1099 DATA_BLOB npa_blob;
1100 struct iovec out_iov;
1102 /* results */
1103 NTSTATUS accept_status;
1104 struct tsocket_address *client;
1105 char *client_name;
1106 struct tsocket_address *server;
1107 char *server_name;
1108 struct netr_SamInfo3 *info3;
1109 DATA_BLOB session_key;
1110 DATA_BLOB delegated_creds;
1113 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1114 void *private_data,
1115 TALLOC_CTX *mem_ctx,
1116 struct iovec **_vector,
1117 size_t *_count);
1118 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1119 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1121 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1122 struct tevent_context *ev,
1123 struct tstream_context *plain,
1124 uint16_t file_type,
1125 uint16_t device_state,
1126 uint64_t allocation_size)
1128 struct tstream_npa_accept_state *state;
1129 struct tevent_req *req, *subreq;
1131 req = tevent_req_create(mem_ctx, &state,
1132 struct tstream_npa_accept_state);
1133 if (req == NULL) {
1134 return NULL;
1137 switch (file_type) {
1138 case FILE_TYPE_BYTE_MODE_PIPE:
1139 break;
1140 case FILE_TYPE_MESSAGE_MODE_PIPE:
1141 break;
1142 default:
1143 tevent_req_error(req, EINVAL);
1144 goto post;
1147 ZERO_STRUCTP(state);
1149 state->ev = ev;
1150 state->plain = plain;
1151 state->file_type = file_type;
1152 state->device_state = device_state;
1153 state->alloc_size = allocation_size;
1156 * The named pipe pdu's have the length as 8 byte (initial_read_size),
1157 * named_pipe_full_request provides the pdu length then.
1159 subreq = tstream_readv_pdu_send(state, ev, plain,
1160 tstream_npa_accept_next_vector,
1161 state);
1162 if (tevent_req_nomem(subreq, req)) {
1163 goto post;
1166 tevent_req_set_callback(subreq,
1167 tstream_npa_accept_existing_reply, req);
1169 return req;
1171 post:
1172 tevent_req_post(req, ev);
1173 return req;
1176 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1177 void *private_data,
1178 TALLOC_CTX *mem_ctx,
1179 struct iovec **_vector,
1180 size_t *_count)
1182 struct tstream_npa_accept_state *state =
1183 talloc_get_type_abort(private_data,
1184 struct tstream_npa_accept_state);
1185 struct iovec *vector;
1186 size_t count;
1187 off_t ofs = 0;
1189 if (state->npa_blob.length == 0) {
1190 state->npa_blob = data_blob_talloc(state, NULL, 4);
1191 if (!state->npa_blob.data) {
1192 return -1;
1194 } else if (state->npa_blob.length == 4) {
1195 uint32_t msg_len;
1197 ofs = 4;
1199 msg_len = RIVAL(state->npa_blob.data, 0);
1201 if (msg_len > 0x00FFFFFF) {
1202 errno = EMSGSIZE;
1203 return -1;
1206 if (msg_len == 0) {
1207 errno = EMSGSIZE;
1208 return -1;
1211 msg_len += ofs;
1213 state->npa_blob.data = talloc_realloc(state,
1214 state->npa_blob.data,
1215 uint8_t, msg_len);
1216 if (!state->npa_blob.data) {
1217 return -1;
1219 state->npa_blob.length = msg_len;
1220 } else {
1221 if (memcmp(&state->npa_blob.data[4],
1222 NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1223 DEBUG(0, ("Wrong protocol\n"));
1224 #if defined(EPROTONOSUPPORT)
1225 errno = EPROTONOSUPPORT;
1226 #elif defined(EPROTO)
1227 errno = EPROTO;
1228 #else
1229 errno = EINVAL;
1230 #endif
1231 return -1;
1233 *_vector = NULL;
1234 *_count = 0;
1235 return 0;
1238 /* we need to get a message header */
1239 vector = talloc_array(mem_ctx, struct iovec, 1);
1240 if (!vector) {
1241 return -1;
1243 vector[0].iov_base = (char *) (state->npa_blob.data + ofs);
1244 vector[0].iov_len = state->npa_blob.length - ofs;
1245 count = 1;
1247 *_vector = vector;
1248 *_count = count;
1249 return 0;
1252 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1254 struct tevent_req *req =
1255 tevent_req_callback_data(subreq, struct tevent_req);
1256 struct tstream_npa_accept_state *state =
1257 tevent_req_data(req, struct tstream_npa_accept_state);
1258 struct named_pipe_auth_req *pipe_request;
1259 struct named_pipe_auth_rep pipe_reply;
1260 struct named_pipe_auth_req_info3 i3;
1261 enum ndr_err_code ndr_err;
1262 DATA_BLOB out;
1263 int sys_errno;
1264 int ret;
1266 ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1267 TALLOC_FREE(subreq);
1268 if (ret == -1) {
1269 tevent_req_error(req, sys_errno);
1270 return;
1273 DEBUG(10, ("Received packet of length %lu\n",
1274 (long)state->npa_blob.length));
1275 dump_data(11, state->npa_blob.data, state->npa_blob.length);
1277 ZERO_STRUCT(pipe_reply);
1278 pipe_reply.level = 0;
1279 pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1281 * TODO: check it's a root (uid == 0) pipe
1284 pipe_request = talloc(state, struct named_pipe_auth_req);
1285 if (!pipe_request) {
1286 DEBUG(0, ("Out of memory!\n"));
1287 goto reply;
1290 /* parse the passed credentials */
1291 ndr_err = ndr_pull_struct_blob_all(
1292 &state->npa_blob, pipe_request, pipe_request,
1293 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1294 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1295 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1296 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1297 nt_errstr(pipe_reply.status)));
1298 goto reply;
1301 if (DEBUGLVL(10)) {
1302 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1305 ZERO_STRUCT(i3);
1307 switch (pipe_request->level) {
1308 case 0:
1309 pipe_reply.level = 0;
1310 pipe_reply.status = NT_STATUS_OK;
1312 /* we need to force byte mode in this level */
1313 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1314 break;
1316 case 1:
1317 pipe_reply.level = 1;
1318 pipe_reply.status = NT_STATUS_OK;
1320 /* We must copy net3_SamInfo3, so that
1321 * info3 is an actual talloc pointer, then we steal
1322 * pipe_request on info3 so that all the allocated memory
1323 * pointed by the structrue members is preserved */
1324 state->info3 = (struct netr_SamInfo3 *)talloc_memdup(state,
1325 &pipe_request->info.info1,
1326 sizeof(struct netr_SamInfo3));
1327 if (!state->info3) {
1328 pipe_reply.status = NT_STATUS_NO_MEMORY;
1329 DEBUG(0, ("Out of memory!\n"));
1330 goto reply;
1332 talloc_steal(state->info3, pipe_request);
1334 /* we need to force byte mode in this level */
1335 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1336 break;
1338 case 2:
1339 pipe_reply.level = 2;
1340 pipe_reply.status = NT_STATUS_OK;
1341 pipe_reply.info.info2.file_type = state->file_type;
1342 pipe_reply.info.info2.device_state = state->device_state;
1343 pipe_reply.info.info2.allocation_size = state->alloc_size;
1345 i3.client_name = pipe_request->info.info2.client_name;
1346 i3.client_addr = pipe_request->info.info2.client_addr;
1347 i3.client_port = pipe_request->info.info2.client_port;
1348 i3.server_name = pipe_request->info.info2.server_name;
1349 i3.server_addr = pipe_request->info.info2.server_addr;
1350 i3.server_port = pipe_request->info.info2.server_port;
1351 i3.sam_info3 = pipe_request->info.info2.sam_info3;
1352 i3.session_key_length =
1353 pipe_request->info.info2.session_key_length;
1354 i3.session_key = pipe_request->info.info2.session_key;
1355 break;
1357 case 3:
1358 pipe_reply.level = 3;
1359 pipe_reply.status = NT_STATUS_OK;
1360 pipe_reply.info.info3.file_type = state->file_type;
1361 pipe_reply.info.info3.device_state = state->device_state;
1362 pipe_reply.info.info3.allocation_size = state->alloc_size;
1364 i3 = pipe_request->info.info3;
1365 break;
1367 default:
1368 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1369 pipe_reply.level = 0;
1370 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1371 goto reply;
1374 if (pipe_reply.level >=2) {
1376 if (i3.server_addr == NULL) {
1377 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1378 DEBUG(2, ("Missing server address\n"));
1379 goto reply;
1381 if (i3.client_addr == NULL) {
1382 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1383 DEBUG(2, ("Missing client address\n"));
1384 goto reply;
1387 state->server_name = discard_const_p(char,
1388 talloc_move(state, &i3.server_name));
1389 ret = tsocket_address_inet_from_strings(state, "ip",
1390 i3.server_addr,
1391 i3.server_port,
1392 &state->server);
1393 if (ret != 0) {
1394 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1395 i3.server_addr, i3.server_port,
1396 strerror(errno)));
1397 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1398 goto reply;
1401 state->client_name = discard_const_p(char,
1402 talloc_move(state, &i3.client_name));
1403 ret = tsocket_address_inet_from_strings(state, "ip",
1404 i3.client_addr,
1405 i3.client_port,
1406 &state->client);
1407 if (ret != 0) {
1408 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1409 i3.client_addr, i3.client_port,
1410 strerror(errno)));
1411 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1412 goto reply;
1415 state->info3 = talloc_move(state, &i3.sam_info3);
1416 state->session_key.data = talloc_move(state, &i3.session_key);
1417 state->session_key.length = i3.session_key_length;
1420 if (pipe_reply.level >= 3) {
1421 state->delegated_creds.data =
1422 talloc_move(state, &i3.gssapi_delegated_creds);
1423 state->delegated_creds.length =
1424 i3.gssapi_delegated_creds_length;
1427 reply:
1428 /* create the output */
1429 ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1430 (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1431 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1432 DEBUG(2, ("Error encoding structure: %s",
1433 ndr_map_error2string(ndr_err)));
1434 tevent_req_error(req, EIO);
1435 return;
1438 DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1439 dump_data(11, out.data, out.length);
1441 if (DEBUGLVL(10)) {
1442 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1445 state->accept_status = pipe_reply.status;
1447 state->out_iov.iov_base = (char *) out.data;
1448 state->out_iov.iov_len = out.length;
1450 subreq = tstream_writev_send(state, state->ev,
1451 state->plain,
1452 &state->out_iov, 1);
1453 if (tevent_req_nomem(subreq, req)) {
1454 DEBUG(0, ("no memory for tstream_writev_send"));
1455 return;
1458 tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1461 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1463 struct tevent_req *req =
1464 tevent_req_callback_data(subreq, struct tevent_req);
1465 int sys_errno;
1466 int ret;
1468 ret = tstream_writev_recv(subreq, &sys_errno);
1469 TALLOC_FREE(subreq);
1470 if (ret == -1) {
1471 tevent_req_error(req, sys_errno);
1472 return;
1475 tevent_req_done(req);
1478 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1479 int *perrno,
1480 TALLOC_CTX *mem_ctx,
1481 struct tstream_context **stream,
1482 struct tsocket_address **client,
1483 char **_client_name,
1484 struct tsocket_address **server,
1485 char **server_name,
1486 struct netr_SamInfo3 **info3,
1487 DATA_BLOB *session_key,
1488 DATA_BLOB *delegated_creds,
1489 const char *location)
1491 struct tstream_npa_accept_state *state =
1492 tevent_req_data(req, struct tstream_npa_accept_state);
1493 struct tstream_npa *npas;
1494 int ret;
1496 ret = tsocket_simple_int_recv(req, perrno);
1497 if (ret != 0) {
1498 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1499 strerror(*perrno)));
1500 tevent_req_received(req);
1501 return -1;
1504 if (!NT_STATUS_IS_OK(state->accept_status)) {
1505 #if defined(EPROTONOSUPPORT)
1506 *perrno = EPROTONOSUPPORT;
1507 #elif defined(EPROTO)
1508 *perrno = EPROTO;
1509 #else
1510 *perrno = EINVAL;
1511 #endif
1512 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1513 nt_errstr(state->accept_status),
1514 strerror(*perrno)));
1515 tevent_req_received(req);
1516 return -1;
1519 *stream = tstream_context_create(mem_ctx,
1520 &tstream_npa_ops,
1521 &npas,
1522 struct tstream_npa,
1523 location);
1524 if (!*stream) {
1525 *perrno = ENOMEM;
1526 tevent_req_received(req);
1527 return -1;
1529 ZERO_STRUCTP(npas);
1530 npas->unix_stream = state->plain;
1531 npas->file_type = state->file_type;
1533 *client = talloc_move(mem_ctx, &state->client);
1534 *_client_name = talloc_move(mem_ctx, &state->client_name);
1535 *server = talloc_move(mem_ctx, &state->server);
1536 *server_name = talloc_move(mem_ctx, &state->server_name);
1537 *info3 = talloc_move(mem_ctx, &state->info3);
1538 *session_key = state->session_key;
1539 talloc_steal(mem_ctx, state->session_key.data);
1540 *delegated_creds = state->delegated_creds;
1541 talloc_steal(mem_ctx, state->delegated_creds.data);
1543 tevent_req_received(req);
1544 return 0;