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