• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/libcli/named_pipe_auth/
1/*
2   Unix SMB/CIFS implementation.
3
4   Copyright (C) Stefan Metzmacher 2009
5
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.
10
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.
15
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/>.
18*/
19
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"
28
29static const struct tstream_context_ops tstream_npa_ops;
30
31struct tstream_npa {
32	struct tstream_context *unix_stream;
33
34	uint16_t file_type;
35
36	struct iovec pending;
37};
38
39struct tstream_npa_connect_state {
40	struct {
41		struct tevent_context *ev;
42		struct smb_iconv_convenience *smb_iconv_c;
43	} caller;
44
45	const char *unix_path;
46	struct tsocket_address *unix_laddr;
47	struct tsocket_address *unix_raddr;
48	struct tstream_context *unix_stream;
49
50	struct named_pipe_auth_req auth_req;
51	DATA_BLOB auth_req_blob;
52	struct iovec auth_req_iov;
53
54	struct named_pipe_auth_rep auth_rep;
55	DATA_BLOB auth_rep_blob;
56};
57
58static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
59
60struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
61					struct tevent_context *ev,
62					struct smb_iconv_convenience *smb_iconv_c,
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)
72{
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
79	req = tevent_req_create(mem_ctx, &state,
80				struct tstream_npa_connect_state);
81	if (!req) {
82		return NULL;
83	}
84
85	state->caller.ev = ev;
86	state->caller.smb_iconv_c = smb_iconv_c;
87
88	state->unix_path = talloc_asprintf(state, "%s/%s",
89					   directory,
90					   npipe);
91	if (tevent_req_nomem(state->unix_path, req)) {
92		goto post;
93	}
94
95	ret = tsocket_address_unix_from_path(state,
96					     "",
97					     &state->unix_laddr);
98	if (ret == -1) {
99		tevent_req_error(req, errno);
100		goto post;
101	}
102
103	ret = tsocket_address_unix_from_path(state,
104					     state->unix_path,
105					     &state->unix_raddr);
106	if (ret == -1) {
107		tevent_req_error(req, errno);
108		goto post;
109	}
110
111	ZERO_STRUCT(state->auth_req);
112	if (client) {
113		struct named_pipe_auth_req_info3 *info3;
114
115		if (!server) {
116			tevent_req_error(req, EINVAL);
117			goto post;
118		}
119
120		state->auth_req.level = 3;
121		info3 = &state->auth_req.info.info3;
122
123		info3->client_name = client_name_in;
124		info3->client_addr = tsocket_address_inet_addr_string(client, state);
125		if (!info3->client_addr) {
126			/* errno might be EINVAL */
127			tevent_req_error(req, errno);
128			goto post;
129		}
130		info3->client_port = tsocket_address_inet_port(client);
131		if (!info3->client_name) {
132			info3->client_name = info3->client_addr;
133		}
134
135		info3->server_addr = tsocket_address_inet_addr_string(server, state);
136		if (!info3->server_addr) {
137			/* errno might be EINVAL */
138			tevent_req_error(req, errno);
139			goto post;
140		}
141		info3->server_port = tsocket_address_inet_port(server);
142		if (!info3->server_name) {
143			info3->server_name = info3->server_addr;
144		}
145
146		info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3);
147		info3->session_key_length = session_key.length;
148		info3->session_key = session_key.data;
149		info3->gssapi_delegated_creds_length = delegated_creds.length;
150		info3->gssapi_delegated_creds = delegated_creds.data;
151
152	} else if (sam_info3) {
153		state->auth_req.level = 1;
154		state->auth_req.info.info1 = *sam_info3;
155	} else {
156		state->auth_req.level = 0;
157	}
158
159	if (DEBUGLVL(10)) {
160		NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
161	}
162
163	ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
164			state, smb_iconv_c, &state->auth_req,
165			(ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
166	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
167		tevent_req_error(req, EINVAL);
168		goto post;
169	}
170
171	state->auth_req_iov.iov_base = state->auth_req_blob.data;
172	state->auth_req_iov.iov_len = state->auth_req_blob.length;
173
174	subreq = tstream_unix_connect_send(state,
175					   state->caller.ev,
176					   state->unix_laddr,
177					   state->unix_raddr);
178	if (tevent_req_nomem(subreq, req)) {
179		goto post;
180	}
181	tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
182
183	return req;
184
185post:
186	tevent_req_post(req, ev);
187	return req;
188}
189
190static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
191
192static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
193{
194	struct tevent_req *req =
195		tevent_req_callback_data(subreq,
196		struct tevent_req);
197	struct tstream_npa_connect_state *state =
198		tevent_req_data(req,
199		struct tstream_npa_connect_state);
200	int ret;
201	int sys_errno;
202
203	ret = tstream_unix_connect_recv(subreq, &sys_errno,
204					state, &state->unix_stream);
205	TALLOC_FREE(subreq);
206	if (ret == -1) {
207		tevent_req_error(req, sys_errno);
208		return;
209	}
210
211	subreq = tstream_writev_send(state,
212				     state->caller.ev,
213				     state->unix_stream,
214				     &state->auth_req_iov, 1);
215	if (tevent_req_nomem(subreq, req)) {
216		return;
217	}
218	tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
219}
220
221static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
222					   void *private_data,
223					   TALLOC_CTX *mem_ctx,
224					   struct iovec **_vector,
225					   size_t *_count);
226static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
227
228static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
229{
230	struct tevent_req *req =
231		tevent_req_callback_data(subreq,
232		struct tevent_req);
233	struct tstream_npa_connect_state *state =
234		tevent_req_data(req,
235		struct tstream_npa_connect_state);
236	int ret;
237	int sys_errno;
238
239	ret = tstream_writev_recv(subreq, &sys_errno);
240	TALLOC_FREE(subreq);
241	if (ret == -1) {
242		tevent_req_error(req, sys_errno);
243		return;
244	}
245
246	state->auth_rep_blob = data_blob_const(NULL, 0);
247
248	subreq = tstream_readv_pdu_send(state, state->caller.ev,
249					state->unix_stream,
250					tstream_npa_connect_next_vector,
251					state);
252	if (tevent_req_nomem(subreq, req)) {
253		return;
254	}
255	tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
256}
257
258static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
259					   void *private_data,
260					   TALLOC_CTX *mem_ctx,
261					   struct iovec **_vector,
262					   size_t *_count)
263{
264	struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
265					struct tstream_npa_connect_state);
266	struct iovec *vector;
267	size_t count;
268	off_t ofs = 0;
269
270	if (state->auth_rep_blob.length == 0) {
271		state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
272		if (!state->auth_rep_blob.data) {
273			return -1;
274		}
275	} else if (state->auth_rep_blob.length == 4) {
276		uint32_t msg_len;
277
278		ofs = 4;
279
280		msg_len = RIVAL(state->auth_rep_blob.data, 0);
281
282		if (msg_len > 0x00FFFFFF) {
283			errno = EMSGSIZE;
284			return -1;
285		}
286
287		if (msg_len == 0) {
288			errno = EMSGSIZE;
289			return -1;
290		}
291
292		msg_len += ofs;
293
294		state->auth_rep_blob.data = talloc_realloc(state,
295						state->auth_rep_blob.data,
296						uint8_t, msg_len);
297		if (!state->auth_rep_blob.data) {
298			return -1;
299		}
300		state->auth_rep_blob.length = msg_len;
301	} else {
302		*_vector = NULL;
303		*_count = 0;
304		return 0;
305	}
306
307	/* we need to get a message header */
308	vector = talloc_array(mem_ctx, struct iovec, 1);
309	if (!vector) {
310		return -1;
311	}
312	vector[0].iov_base = state->auth_rep_blob.data + ofs;
313	vector[0].iov_len = state->auth_rep_blob.length - ofs;
314	count = 1;
315
316	*_vector = vector;
317	*_count = count;
318	return 0;
319}
320
321static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
322{
323	struct tevent_req *req =
324		tevent_req_callback_data(subreq,
325		struct tevent_req);
326	struct tstream_npa_connect_state *state =
327		tevent_req_data(req,
328		struct tstream_npa_connect_state);
329	int ret;
330	int sys_errno;
331	enum ndr_err_code ndr_err;
332
333	ret = tstream_readv_pdu_recv(subreq, &sys_errno);
334	TALLOC_FREE(subreq);
335	if (ret == -1) {
336		tevent_req_error(req, sys_errno);
337		return;
338	}
339
340	DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
341		 (uint32_t)state->auth_rep_blob.length));
342	dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
343
344	ndr_err = ndr_pull_struct_blob(
345		&state->auth_rep_blob, state,
346		state->caller.smb_iconv_c, &state->auth_rep,
347		(ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
348
349	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
350		DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
351			  ndr_map_error2string(ndr_err)));
352		tevent_req_error(req, EIO);
353		return;
354	}
355
356	if (DEBUGLVL(10)) {
357		NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
358	}
359
360	if (state->auth_rep.length < 16) {
361		DEBUG(0, ("req invalid length: %u < 16\n",
362			  state->auth_rep.length));
363		tevent_req_error(req, EIO);
364		return;
365	}
366
367	if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
368		DEBUG(0, ("req invalid magic: %s != %s\n",
369			  state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
370		tevent_req_error(req, EIO);
371		return;
372	}
373
374	if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
375		DEBUG(0, ("req failed: %s\n",
376			  nt_errstr(state->auth_rep.status)));
377		tevent_req_error(req, EACCES);
378		return;
379	}
380
381	if (state->auth_rep.level != state->auth_req.level) {
382		DEBUG(0, ("req invalid level: %u != %u\n",
383			  state->auth_rep.level, state->auth_req.level));
384		tevent_req_error(req, EIO);
385		return;
386	}
387
388	tevent_req_done(req);
389}
390
391int _tstream_npa_connect_recv(struct tevent_req *req,
392			      int *perrno,
393			      TALLOC_CTX *mem_ctx,
394			      struct tstream_context **_stream,
395			      uint16_t *_file_type,
396			      uint16_t *_device_state,
397			      uint64_t *_allocation_size,
398			      const char *location)
399{
400	struct tstream_npa_connect_state *state =
401		tevent_req_data(req,
402		struct tstream_npa_connect_state);
403	struct tstream_context *stream;
404	struct tstream_npa *npas;
405	uint16_t device_state = 0;
406	uint64_t allocation_size = 0;
407
408	if (tevent_req_is_unix_error(req, perrno)) {
409		tevent_req_received(req);
410		return -1;
411	}
412
413	stream = tstream_context_create(mem_ctx,
414					&tstream_npa_ops,
415					&npas,
416					struct tstream_npa,
417					location);
418	if (!stream) {
419		return -1;
420	}
421	ZERO_STRUCTP(npas);
422
423	npas->unix_stream = talloc_move(stream, &state->unix_stream);
424	switch (state->auth_rep.level) {
425	case 0:
426	case 1:
427		npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
428		device_state = 0x00ff;
429		allocation_size = 2048;
430		break;
431	case 2:
432		npas->file_type = state->auth_rep.info.info2.file_type;
433		device_state = state->auth_rep.info.info2.device_state;
434		allocation_size = state->auth_rep.info.info2.allocation_size;
435		break;
436	case 3:
437		npas->file_type = state->auth_rep.info.info3.file_type;
438		device_state = state->auth_rep.info.info3.device_state;
439		allocation_size = state->auth_rep.info.info3.allocation_size;
440		break;
441	}
442
443	*_stream = stream;
444	*_file_type = npas->file_type;
445	*_device_state = device_state;
446	*_allocation_size = allocation_size;
447	tevent_req_received(req);
448	return 0;
449}
450
451static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
452{
453	struct tstream_npa *npas = tstream_context_data(stream,
454				   struct tstream_npa);
455	ssize_t ret;
456
457	if (!npas->unix_stream) {
458		errno = ENOTCONN;
459		return -1;
460	}
461
462	switch (npas->file_type) {
463	case FILE_TYPE_BYTE_MODE_PIPE:
464		ret = tstream_pending_bytes(npas->unix_stream);
465		break;
466
467	case FILE_TYPE_MESSAGE_MODE_PIPE:
468		ret = npas->pending.iov_len;
469		break;
470
471	default:
472		ret = -1;
473	}
474
475	return ret;
476}
477
478struct tstream_npa_readv_state {
479	struct tstream_context *stream;
480
481	struct iovec *vector;
482	size_t count;
483
484	/* the header for message mode */
485	uint8_t hdr[2];
486	bool wait_for_hdr;
487
488	int ret;
489};
490
491static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
492static int tstream_npa_readv_next_vector(struct tstream_context *stream,
493					 void *private_data,
494					 TALLOC_CTX *mem_ctx,
495					 struct iovec **_vector,
496					 size_t *_count);
497static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
498
499static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
500					struct tevent_context *ev,
501					struct tstream_context *stream,
502					struct iovec *vector,
503					size_t count)
504{
505	struct tevent_req *req;
506	struct tstream_npa_readv_state *state;
507	struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
508	struct tevent_req *subreq;
509	off_t ofs;
510	size_t left;
511	uint8_t *pbase;
512
513	req = tevent_req_create(mem_ctx, &state,
514				struct tstream_npa_readv_state);
515	if (!req) {
516		return NULL;
517	}
518
519	state->stream	= stream;
520	state->ret	= 0;
521
522	if (!npas->unix_stream) {
523		tevent_req_error(req, ENOTCONN);
524		goto post;
525	}
526
527	switch (npas->file_type) {
528	case FILE_TYPE_BYTE_MODE_PIPE:
529		state->vector = vector;
530		state->count = count;
531
532		subreq = tstream_readv_send(state,
533					    ev,
534					    npas->unix_stream,
535					    state->vector,
536					    state->count);
537		if (tevent_req_nomem(subreq,req)) {
538			goto post;
539		}
540		tevent_req_set_callback(subreq,
541					tstream_npa_readv_byte_mode_handler,
542					req);
543
544		return req;
545
546	case FILE_TYPE_MESSAGE_MODE_PIPE:
547		/*
548		 * we make a copy of the vector and prepend a header
549		 * with the length
550		 */
551		state->vector	= talloc_array(state, struct iovec, count);
552		if (tevent_req_nomem(state->vector, req)) {
553			goto post;
554		}
555		memcpy(state->vector, vector, sizeof(struct iovec)*count);
556		state->count = count;
557
558		/*
559		 * copy the pending buffer first
560		 */
561		ofs = 0;
562		left = npas->pending.iov_len;
563		pbase = (uint8_t *)npas->pending.iov_base;
564
565		while (left > 0 && state->count > 0) {
566			uint8_t *base;
567			base = (uint8_t *)state->vector[0].iov_base;
568			if (left < state->vector[0].iov_len) {
569				memcpy(base, pbase + ofs, left);
570
571				base += left;
572				state->vector[0].iov_base = base;
573				state->vector[0].iov_len -= left;
574
575				ofs += left;
576				left = 0;
577				TALLOC_FREE(pbase);
578				ZERO_STRUCT(npas->pending);
579				break;
580			}
581			memcpy(base, pbase + ofs, state->vector[0].iov_len);
582
583			ofs += state->vector[0].iov_len;
584			left -= state->vector[0].iov_len;
585			state->vector += 1;
586			state->count -= 1;
587
588			if (left == 0) {
589				TALLOC_FREE(pbase);
590				ZERO_STRUCT(npas->pending);
591				break;
592			}
593		}
594
595		if (left > 0) {
596			memmove(pbase, pbase + ofs, left);
597			npas->pending.iov_base = pbase;
598			npas->pending.iov_len = left;
599			/*
600			 * this cannot fail and even if it
601			 * fails we can handle it
602			 */
603			pbase = talloc_realloc(npas, pbase, uint8_t, left);
604			if (pbase) {
605				npas->pending.iov_base = pbase;
606			}
607			pbase = NULL;
608		}
609
610		state->ret += ofs;
611
612		if (state->count == 0) {
613			tevent_req_done(req);
614			goto post;
615		}
616
617		ZERO_STRUCT(state->hdr);
618		state->wait_for_hdr = false;
619
620		subreq = tstream_readv_pdu_send(state,
621						ev,
622						npas->unix_stream,
623						tstream_npa_readv_next_vector,
624						state);
625		if (tevent_req_nomem(subreq, req)) {
626			goto post;
627		}
628		tevent_req_set_callback(subreq,
629					tstream_npa_readv_msg_mode_handler,
630					req);
631
632		return req;
633	}
634
635	/* this can't happen */
636	tevent_req_error(req, EINVAL);
637	goto post;
638
639 post:
640	tevent_req_post(req, ev);
641	return req;
642}
643
644static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
645{
646	struct tevent_req *req = tevent_req_callback_data(subreq,
647				 struct tevent_req);
648	struct tstream_npa_readv_state *state = tevent_req_data(req,
649					struct tstream_npa_readv_state);
650	int ret;
651	int sys_errno;
652
653	ret = tstream_readv_recv(subreq, &sys_errno);
654	TALLOC_FREE(subreq);
655	if (ret == -1) {
656		tevent_req_error(req, sys_errno);
657		return;
658	}
659
660	state->ret = ret;
661
662	tevent_req_done(req);
663}
664
665static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
666					 void *private_data,
667					 TALLOC_CTX *mem_ctx,
668					 struct iovec **_vector,
669					 size_t *_count)
670{
671	struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
672					struct tstream_npa_readv_state);
673	struct tstream_npa *npas = tstream_context_data(state->stream,
674				   struct tstream_npa);
675	struct iovec *vector;
676	size_t count;
677	uint16_t msg_len;
678	size_t left;
679
680	if (state->count == 0) {
681		*_vector = NULL;
682		*_count = 0;
683		return 0;
684	}
685
686	if (!state->wait_for_hdr) {
687		/* we need to get a message header */
688		vector = talloc_array(mem_ctx, struct iovec, 1);
689		if (!vector) {
690			return -1;
691		}
692		ZERO_STRUCT(state->hdr);
693		vector[0].iov_base = state->hdr;
694		vector[0].iov_len = sizeof(state->hdr);
695
696		count = 1;
697
698		state->wait_for_hdr = true;
699
700		*_vector = vector;
701		*_count = count;
702		return 0;
703	}
704
705	/* and now fill the callers buffers and maybe the pending buffer */
706	state->wait_for_hdr = false;
707
708	msg_len = SVAL(state->hdr, 0);
709
710	if (msg_len == 0) {
711		errno = EIO;
712		return -1;
713	}
714
715	state->wait_for_hdr = false;
716
717	/* +1 because we may need to fill the pending buffer */
718	vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
719	if (!vector) {
720		return -1;
721	}
722
723	count = 0;
724	left = msg_len;
725	while (left > 0 && state->count > 0) {
726		if (left < state->vector[0].iov_len) {
727			uint8_t *base;
728			base = (uint8_t *)state->vector[0].iov_base;
729			vector[count].iov_base = base;
730			vector[count].iov_len = left;
731			count++;
732			base += left;
733			state->vector[0].iov_base = base;
734			state->vector[0].iov_len -= left;
735			break;
736		}
737		vector[count] = state->vector[0];
738		count++;
739		left -= state->vector[0].iov_len;
740		state->vector += 1;
741		state->count -= 1;
742	}
743
744	if (left > 0) {
745		/*
746		 * if the message if longer than the buffers the caller
747		 * requested, we need to consume the rest of the message
748		 * into the pending buffer, where the next readv can
749		 * be served from.
750		 */
751		npas->pending.iov_base = talloc_array(npas, uint8_t, left);
752		if (!npas->pending.iov_base) {
753			return -1;
754		}
755		npas->pending.iov_len = left;
756
757		vector[count] = npas->pending;
758		count++;
759	}
760
761	state->ret += (msg_len - left);
762
763	*_vector = vector;
764	*_count = count;
765	return 0;
766}
767
768static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
769{
770	struct tevent_req *req = tevent_req_callback_data(subreq,
771				 struct tevent_req);
772	int ret;
773	int sys_errno;
774
775	ret = tstream_readv_pdu_recv(subreq, &sys_errno);
776	TALLOC_FREE(subreq);
777	if (ret == -1) {
778		tevent_req_error(req, sys_errno);
779		return;
780	}
781
782	/*
783	 * we do not set state->ret here as ret includes the headr size.
784	 * we set it in tstream_npa_readv_pdu_next_vector()
785	 */
786
787	tevent_req_done(req);
788}
789
790static int tstream_npa_readv_recv(struct tevent_req *req,
791				   int *perrno)
792{
793	struct tstream_npa_readv_state *state = tevent_req_data(req,
794					struct tstream_npa_readv_state);
795	int ret;
796
797	ret = tsocket_simple_int_recv(req, perrno);
798	if (ret == 0) {
799		ret = state->ret;
800	}
801
802	tevent_req_received(req);
803	return ret;
804}
805
806struct tstream_npa_writev_state {
807	const struct iovec *vector;
808	size_t count;
809
810	/* the header for message mode */
811	uint8_t hdr[2];
812
813	int ret;
814};
815
816static void tstream_npa_writev_handler(struct tevent_req *subreq);
817
818static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
819					struct tevent_context *ev,
820					struct tstream_context *stream,
821					const struct iovec *vector,
822					size_t count)
823{
824	struct tevent_req *req;
825	struct tstream_npa_writev_state *state;
826	struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
827	struct tevent_req *subreq;
828	size_t msg_len;
829	size_t i;
830	struct iovec *new_vector;
831
832	req = tevent_req_create(mem_ctx, &state,
833				struct tstream_npa_writev_state);
834	if (!req) {
835		return NULL;
836	}
837
838	state->ret	= 0;
839
840	if (!npas->unix_stream) {
841		tevent_req_error(req, ENOTCONN);
842		goto post;
843	}
844
845	switch (npas->file_type) {
846	case FILE_TYPE_BYTE_MODE_PIPE:
847		state->vector	= vector;
848		state->count	= count;
849		break;
850
851	case FILE_TYPE_MESSAGE_MODE_PIPE:
852		/*
853		 * we make a copy of the vector and prepend a header
854		 * with the length
855		 */
856		new_vector	= talloc_array(state, struct iovec, count + 1);
857		if (tevent_req_nomem(new_vector, req)) {
858			goto post;
859		}
860		new_vector[0].iov_base = state->hdr;
861		new_vector[0].iov_len = sizeof(state->hdr);
862		memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
863
864		state->vector	= new_vector;
865		state->count	= count + 1;
866
867		msg_len = 0;
868		for (i=0; i < count; i++) {
869			msg_len += vector[i].iov_len;
870		}
871
872		if (msg_len > UINT16_MAX) {
873			tevent_req_error(req, EMSGSIZE);
874			goto post;
875		}
876
877		SSVAL(state->hdr, 0, msg_len);
878		break;
879	}
880
881	subreq = tstream_writev_send(state,
882				     ev,
883				     npas->unix_stream,
884				     state->vector,
885				     state->count);
886	if (tevent_req_nomem(subreq, req)) {
887		goto post;
888	}
889	tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
890
891	return req;
892
893 post:
894	tevent_req_post(req, ev);
895	return req;
896}
897
898static void tstream_npa_writev_handler(struct tevent_req *subreq)
899{
900	struct tevent_req *req = tevent_req_callback_data(subreq,
901				 struct tevent_req);
902	struct tstream_npa_writev_state *state = tevent_req_data(req,
903					struct tstream_npa_writev_state);
904	int ret;
905	int sys_errno;
906
907	ret = tstream_writev_recv(subreq, &sys_errno);
908	TALLOC_FREE(subreq);
909	if (ret == -1) {
910		tevent_req_error(req, sys_errno);
911		return;
912	}
913
914	state->ret = ret;
915
916	tevent_req_done(req);
917}
918
919static int tstream_npa_writev_recv(struct tevent_req *req,
920				   int *perrno)
921{
922	struct tstream_npa_writev_state *state = tevent_req_data(req,
923					struct tstream_npa_writev_state);
924	int ret;
925
926	ret = tsocket_simple_int_recv(req, perrno);
927	if (ret == 0) {
928		ret = state->ret;
929	}
930
931	tevent_req_received(req);
932	return ret;
933}
934
935struct tstream_npa_disconnect_state {
936	struct tstream_context *stream;
937};
938
939static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
940
941static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
942						struct tevent_context *ev,
943						struct tstream_context *stream)
944{
945	struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
946	struct tevent_req *req;
947	struct tstream_npa_disconnect_state *state;
948	struct tevent_req *subreq;
949
950	req = tevent_req_create(mem_ctx, &state,
951				struct tstream_npa_disconnect_state);
952	if (req == NULL) {
953		return NULL;
954	}
955
956	state->stream = stream;
957
958	if (!npas->unix_stream) {
959		tevent_req_error(req, ENOTCONN);
960		goto post;
961	}
962
963	subreq = tstream_disconnect_send(state,
964					 ev,
965					 npas->unix_stream);
966	if (tevent_req_nomem(subreq, req)) {
967		goto post;
968	}
969	tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
970
971	return req;
972
973post:
974	tevent_req_post(req, ev);
975	return req;
976}
977
978static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
979{
980	struct tevent_req *req = tevent_req_callback_data(subreq,
981				 struct tevent_req);
982	struct tstream_npa_disconnect_state *state = tevent_req_data(req,
983					struct tstream_npa_disconnect_state);
984	struct tstream_context *stream = state->stream;
985	struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
986	int ret;
987	int sys_errno;
988
989	ret = tstream_disconnect_recv(subreq, &sys_errno);
990	TALLOC_FREE(subreq);
991	if (ret == -1) {
992		tevent_req_error(req, sys_errno);
993		return;
994	}
995
996	TALLOC_FREE(npas->unix_stream);
997
998	tevent_req_done(req);
999}
1000
1001static int tstream_npa_disconnect_recv(struct tevent_req *req,
1002				       int *perrno)
1003{
1004	int ret;
1005
1006	ret = tsocket_simple_int_recv(req, perrno);
1007
1008	tevent_req_received(req);
1009	return ret;
1010}
1011
1012static const struct tstream_context_ops tstream_npa_ops = {
1013	.name			= "npa",
1014
1015	.pending_bytes		= tstream_npa_pending_bytes,
1016
1017	.readv_send		= tstream_npa_readv_send,
1018	.readv_recv		= tstream_npa_readv_recv,
1019
1020	.writev_send		= tstream_npa_writev_send,
1021	.writev_recv		= tstream_npa_writev_recv,
1022
1023	.disconnect_send	= tstream_npa_disconnect_send,
1024	.disconnect_recv	= tstream_npa_disconnect_recv,
1025};
1026
1027int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1028				 int fd,
1029				 uint16_t file_type,
1030				 struct tstream_context **_stream,
1031				 const char *location)
1032{
1033	struct tstream_context *stream;
1034	struct tstream_npa *npas;
1035	int ret;
1036
1037	switch (file_type) {
1038	case FILE_TYPE_BYTE_MODE_PIPE:
1039		break;
1040	case FILE_TYPE_MESSAGE_MODE_PIPE:
1041		break;
1042	default:
1043		errno = EINVAL;
1044		return -1;
1045	}
1046
1047	stream = tstream_context_create(mem_ctx,
1048					&tstream_npa_ops,
1049					&npas,
1050					struct tstream_npa,
1051					location);
1052	if (!stream) {
1053		return -1;
1054	}
1055	ZERO_STRUCTP(npas);
1056
1057	npas->file_type = file_type;
1058
1059	ret = tstream_bsd_existing_socket(stream, fd,
1060					  &npas->unix_stream);
1061	if (ret == -1) {
1062		int saved_errno = errno;
1063		talloc_free(stream);
1064		errno = saved_errno;
1065		return -1;
1066	}
1067
1068	*_stream = stream;
1069	return 0;
1070}
1071
1072