20ae3de815486117bbcbc9a120f699828efd16c2
[samba.git] / libcli / named_pipe_auth / npa_tstream.c
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/smb/smb_constants.h"
28
29 static const struct tstream_context_ops tstream_npa_ops;
30
31 struct tstream_npa {
32         struct tstream_context *unix_stream;
33
34         uint16_t file_type;
35
36         struct iovec pending;
37 };
38
39 struct tstream_npa_connect_state {
40         struct {
41                 struct tevent_context *ev;
42         } caller;
43
44         const char *unix_path;
45         struct tsocket_address *unix_laddr;
46         struct tsocket_address *unix_raddr;
47         struct tstream_context *unix_stream;
48
49         struct named_pipe_auth_req auth_req;
50         DATA_BLOB auth_req_blob;
51         struct iovec auth_req_iov;
52
53         struct named_pipe_auth_rep auth_rep;
54         DATA_BLOB auth_rep_blob;
55 };
56
57 static void tstream_npa_connect_unix_done(struct tevent_req *subreq);
58
59 struct tevent_req *tstream_npa_connect_send(TALLOC_CTX *mem_ctx,
60                                             struct tevent_context *ev,
61                                             const char *directory,
62                                             const char *npipe,
63                                             const struct tsocket_address *client,
64                                             const char *client_name_in,
65                                             const struct tsocket_address *server,
66                                             const char *server_name,
67                                             const struct auth_session_info_transport *session_info)
68 {
69         struct tevent_req *req;
70         struct tstream_npa_connect_state *state;
71         struct tevent_req *subreq;
72         int ret;
73         enum ndr_err_code ndr_err;
74         char *lower_case_npipe;
75         struct named_pipe_auth_req_info4 *info4;
76
77         req = tevent_req_create(mem_ctx, &state,
78                                 struct tstream_npa_connect_state);
79         if (!req) {
80                 return NULL;
81         }
82
83         state->caller.ev = ev;
84
85         lower_case_npipe = strlower_talloc(state, npipe);
86         if (tevent_req_nomem(lower_case_npipe, req)) {
87                 goto post;
88         }
89
90         state->unix_path = talloc_asprintf(state, "%s/%s",
91                                            directory,
92                                            lower_case_npipe);
93         talloc_free(lower_case_npipe);
94         if (tevent_req_nomem(state->unix_path, req)) {
95                 goto post;
96         }
97
98         ret = tsocket_address_unix_from_path(state,
99                                              "",
100                                              &state->unix_laddr);
101         if (ret == -1) {
102                 tevent_req_error(req, errno);
103                 goto post;
104         }
105
106         ret = tsocket_address_unix_from_path(state,
107                                              state->unix_path,
108                                              &state->unix_raddr);
109         if (ret == -1) {
110                 tevent_req_error(req, errno);
111                 goto post;
112         }
113
114         ZERO_STRUCT(state->auth_req);
115
116         if (!server) {
117                 tevent_req_error(req, EINVAL);
118                 goto post;
119         }
120
121         state->auth_req.level = 4;
122         info4 = &state->auth_req.info.info4;
123
124         info4->client_name = client_name_in;
125         info4->client_addr = tsocket_address_inet_addr_string(client, state);
126         if (!info4->client_addr) {
127                 /* errno might be EINVAL */
128                 tevent_req_error(req, errno);
129                 goto post;
130         }
131         info4->client_port = tsocket_address_inet_port(client);
132         if (!info4->client_name) {
133                 info4->client_name = info4->client_addr;
134         }
135
136         info4->server_addr = tsocket_address_inet_addr_string(server, state);
137         if (!info4->server_addr) {
138                 /* errno might be EINVAL */
139                 tevent_req_error(req, errno);
140                 goto post;
141         }
142         info4->server_port = tsocket_address_inet_port(server);
143         if (!info4->server_name) {
144                 info4->server_name = info4->server_addr;
145         }
146
147         info4->session_info = discard_const_p(struct auth_session_info_transport, session_info);
148
149         if (DEBUGLVL(10)) {
150                 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
151         }
152
153         ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
154                         state, &state->auth_req,
155                         (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
156         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157                 tevent_req_error(req, EINVAL);
158                 goto post;
159         }
160
161         state->auth_req_iov.iov_base = (char *) state->auth_req_blob.data;
162         state->auth_req_iov.iov_len = state->auth_req_blob.length;
163
164         subreq = tstream_unix_connect_send(state,
165                                            state->caller.ev,
166                                            state->unix_laddr,
167                                            state->unix_raddr);
168         if (tevent_req_nomem(subreq, req)) {
169                 goto post;
170         }
171         tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
172
173         return req;
174
175 post:
176         tevent_req_post(req, ev);
177         return req;
178 }
179
180 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
181
182 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
183 {
184         struct tevent_req *req =
185                 tevent_req_callback_data(subreq,
186                 struct tevent_req);
187         struct tstream_npa_connect_state *state =
188                 tevent_req_data(req,
189                 struct tstream_npa_connect_state);
190         int ret;
191         int sys_errno;
192
193         ret = tstream_unix_connect_recv(subreq, &sys_errno,
194                                         state, &state->unix_stream);
195         TALLOC_FREE(subreq);
196         if (ret == -1) {
197                 tevent_req_error(req, sys_errno);
198                 return;
199         }
200
201         subreq = tstream_writev_send(state,
202                                      state->caller.ev,
203                                      state->unix_stream,
204                                      &state->auth_req_iov, 1);
205         if (tevent_req_nomem(subreq, req)) {
206                 return;
207         }
208         tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
209 }
210
211 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
212                                            void *private_data,
213                                            TALLOC_CTX *mem_ctx,
214                                            struct iovec **_vector,
215                                            size_t *_count);
216 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
217
218 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
219 {
220         struct tevent_req *req =
221                 tevent_req_callback_data(subreq,
222                 struct tevent_req);
223         struct tstream_npa_connect_state *state =
224                 tevent_req_data(req,
225                 struct tstream_npa_connect_state);
226         int ret;
227         int sys_errno;
228
229         ret = tstream_writev_recv(subreq, &sys_errno);
230         TALLOC_FREE(subreq);
231         if (ret == -1) {
232                 tevent_req_error(req, sys_errno);
233                 return;
234         }
235
236         state->auth_rep_blob = data_blob_const(NULL, 0);
237
238         subreq = tstream_readv_pdu_send(state, state->caller.ev,
239                                         state->unix_stream,
240                                         tstream_npa_connect_next_vector,
241                                         state);
242         if (tevent_req_nomem(subreq, req)) {
243                 return;
244         }
245         tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
246 }
247
248 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
249                                            void *private_data,
250                                            TALLOC_CTX *mem_ctx,
251                                            struct iovec **_vector,
252                                            size_t *_count)
253 {
254         struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
255                                         struct tstream_npa_connect_state);
256         struct iovec *vector;
257         size_t count;
258         off_t ofs = 0;
259
260         if (state->auth_rep_blob.length == 0) {
261                 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
262                 if (!state->auth_rep_blob.data) {
263                         return -1;
264                 }
265         } else if (state->auth_rep_blob.length == 4) {
266                 uint32_t msg_len;
267
268                 ofs = 4;
269
270                 msg_len = RIVAL(state->auth_rep_blob.data, 0);
271
272                 if (msg_len > 0x00FFFFFF) {
273                         errno = EMSGSIZE;
274                         return -1;
275                 }
276
277                 if (msg_len == 0) {
278                         errno = EMSGSIZE;
279                         return -1;
280                 }
281
282                 msg_len += ofs;
283
284                 state->auth_rep_blob.data = talloc_realloc(state,
285                                                 state->auth_rep_blob.data,
286                                                 uint8_t, msg_len);
287                 if (!state->auth_rep_blob.data) {
288                         return -1;
289                 }
290                 state->auth_rep_blob.length = msg_len;
291         } else {
292                 *_vector = NULL;
293                 *_count = 0;
294                 return 0;
295         }
296
297         /* we need to get a message header */
298         vector = talloc_array(mem_ctx, struct iovec, 1);
299         if (!vector) {
300                 return -1;
301         }
302         vector[0].iov_base = (char *) (state->auth_rep_blob.data + ofs);
303         vector[0].iov_len = state->auth_rep_blob.length - ofs;
304         count = 1;
305
306         *_vector = vector;
307         *_count = count;
308         return 0;
309 }
310
311 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
312 {
313         struct tevent_req *req =
314                 tevent_req_callback_data(subreq,
315                 struct tevent_req);
316         struct tstream_npa_connect_state *state =
317                 tevent_req_data(req,
318                 struct tstream_npa_connect_state);
319         int ret;
320         int sys_errno;
321         enum ndr_err_code ndr_err;
322
323         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
324         TALLOC_FREE(subreq);
325         if (ret == -1) {
326                 tevent_req_error(req, sys_errno);
327                 return;
328         }
329
330         DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
331                  (uint32_t)state->auth_rep_blob.length));
332         dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
333
334         ndr_err = ndr_pull_struct_blob(
335                 &state->auth_rep_blob, state,
336                 &state->auth_rep,
337                 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
338
339         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
340                 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
341                           ndr_map_error2string(ndr_err)));
342                 tevent_req_error(req, EIO);
343                 return;
344         }
345
346         if (DEBUGLVL(10)) {
347                 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
348         }
349
350         if (state->auth_rep.length < 16) {
351                 DEBUG(0, ("req invalid length: %u < 16\n",
352                           state->auth_rep.length));
353                 tevent_req_error(req, EIO);
354                 return;
355         }
356
357         if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
358                 DEBUG(0, ("req invalid magic: %s != %s\n",
359                           state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
360                 tevent_req_error(req, EIO);
361                 return;
362         }
363
364         if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
365                 DEBUG(0, ("req failed: %s\n",
366                           nt_errstr(state->auth_rep.status)));
367                 tevent_req_error(req, EACCES);
368                 return;
369         }
370
371         if (state->auth_rep.level != state->auth_req.level) {
372                 DEBUG(0, ("req invalid level: %u != %u\n",
373                           state->auth_rep.level, state->auth_req.level));
374                 tevent_req_error(req, EIO);
375                 return;
376         }
377
378         tevent_req_done(req);
379 }
380
381 int _tstream_npa_connect_recv(struct tevent_req *req,
382                               int *perrno,
383                               TALLOC_CTX *mem_ctx,
384                               struct tstream_context **_stream,
385                               uint16_t *_file_type,
386                               uint16_t *_device_state,
387                               uint64_t *_allocation_size,
388                               const char *location)
389 {
390         struct tstream_npa_connect_state *state =
391                 tevent_req_data(req,
392                 struct tstream_npa_connect_state);
393         struct tstream_context *stream;
394         struct tstream_npa *npas;
395         uint16_t device_state = 0;
396         uint64_t allocation_size = 0;
397
398         if (tevent_req_is_unix_error(req, perrno)) {
399                 tevent_req_received(req);
400                 return -1;
401         }
402
403         stream = tstream_context_create(mem_ctx,
404                                         &tstream_npa_ops,
405                                         &npas,
406                                         struct tstream_npa,
407                                         location);
408         if (!stream) {
409                 *perrno = ENOMEM;
410                 tevent_req_received(req);
411                 return -1;
412         }
413         ZERO_STRUCTP(npas);
414
415         npas->unix_stream = talloc_move(stream, &state->unix_stream);
416         switch (state->auth_rep.level) {
417         case 4:
418                 npas->file_type = state->auth_rep.info.info4.file_type;
419                 device_state = state->auth_rep.info.info4.device_state;
420                 allocation_size = state->auth_rep.info.info4.allocation_size;
421                 break;
422         }
423
424         *_stream = stream;
425         *_file_type = npas->file_type;
426         *_device_state = device_state;
427         *_allocation_size = allocation_size;
428         tevent_req_received(req);
429         return 0;
430 }
431
432 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
433 {
434         struct tstream_npa *npas = tstream_context_data(stream,
435                                    struct tstream_npa);
436         ssize_t ret;
437
438         if (!npas->unix_stream) {
439                 errno = ENOTCONN;
440                 return -1;
441         }
442
443         switch (npas->file_type) {
444         case FILE_TYPE_BYTE_MODE_PIPE:
445                 ret = tstream_pending_bytes(npas->unix_stream);
446                 break;
447
448         case FILE_TYPE_MESSAGE_MODE_PIPE:
449                 ret = npas->pending.iov_len;
450                 break;
451
452         default:
453                 ret = -1;
454         }
455
456         return ret;
457 }
458
459 struct tstream_npa_readv_state {
460         struct tstream_context *stream;
461
462         struct iovec *vector;
463         size_t count;
464
465         /* the header for message mode */
466         uint8_t hdr[2];
467         bool wait_for_hdr;
468
469         int ret;
470 };
471
472 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
473 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
474                                          void *private_data,
475                                          TALLOC_CTX *mem_ctx,
476                                          struct iovec **_vector,
477                                          size_t *_count);
478 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
479
480 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
481                                         struct tevent_context *ev,
482                                         struct tstream_context *stream,
483                                         struct iovec *vector,
484                                         size_t count)
485 {
486         struct tevent_req *req;
487         struct tstream_npa_readv_state *state;
488         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
489         struct tevent_req *subreq;
490         off_t ofs;
491         size_t left;
492         uint8_t *pbase;
493
494         req = tevent_req_create(mem_ctx, &state,
495                                 struct tstream_npa_readv_state);
496         if (!req) {
497                 return NULL;
498         }
499
500         state->stream   = stream;
501         state->ret      = 0;
502
503         if (!npas->unix_stream) {
504                 tevent_req_error(req, ENOTCONN);
505                 goto post;
506         }
507
508         switch (npas->file_type) {
509         case FILE_TYPE_BYTE_MODE_PIPE:
510                 state->vector = vector;
511                 state->count = count;
512
513                 subreq = tstream_readv_send(state,
514                                             ev,
515                                             npas->unix_stream,
516                                             state->vector,
517                                             state->count);
518                 if (tevent_req_nomem(subreq,req)) {
519                         goto post;
520                 }
521                 tevent_req_set_callback(subreq,
522                                         tstream_npa_readv_byte_mode_handler,
523                                         req);
524
525                 return req;
526
527         case FILE_TYPE_MESSAGE_MODE_PIPE:
528                 /*
529                  * we make a copy of the vector and prepend a header
530                  * with the length
531                  */
532                 state->vector   = talloc_array(state, struct iovec, count);
533                 if (tevent_req_nomem(state->vector, req)) {
534                         goto post;
535                 }
536                 memcpy(state->vector, vector, sizeof(struct iovec)*count);
537                 state->count = count;
538
539                 /*
540                  * copy the pending buffer first
541                  */
542                 ofs = 0;
543                 left = npas->pending.iov_len;
544                 pbase = (uint8_t *)npas->pending.iov_base;
545
546                 while (left > 0 && state->count > 0) {
547                         uint8_t *base;
548                         base = (uint8_t *)state->vector[0].iov_base;
549                         if (left < state->vector[0].iov_len) {
550                                 memcpy(base, pbase + ofs, left);
551
552                                 base += left;
553                                 state->vector[0].iov_base = (char *) base;
554                                 state->vector[0].iov_len -= left;
555
556                                 ofs += left;
557                                 left = 0;
558                                 TALLOC_FREE(pbase);
559                                 ZERO_STRUCT(npas->pending);
560                                 break;
561                         }
562                         memcpy(base, pbase + ofs, state->vector[0].iov_len);
563
564                         ofs += state->vector[0].iov_len;
565                         left -= state->vector[0].iov_len;
566                         state->vector += 1;
567                         state->count -= 1;
568
569                         if (left == 0) {
570                                 TALLOC_FREE(pbase);
571                                 ZERO_STRUCT(npas->pending);
572                                 break;
573                         }
574                 }
575
576                 if (left > 0) {
577                         memmove(pbase, pbase + ofs, left);
578                         npas->pending.iov_base = (char *) pbase;
579                         npas->pending.iov_len = left;
580                         /*
581                          * this cannot fail and even if it
582                          * fails we can handle it
583                          */
584                         pbase = talloc_realloc(npas, pbase, uint8_t, left);
585                         if (pbase) {
586                                 npas->pending.iov_base = (char *) pbase;
587                         }
588                         pbase = NULL;
589                 }
590
591                 state->ret += ofs;
592
593                 if (state->count == 0) {
594                         tevent_req_done(req);
595                         goto post;
596                 }
597
598                 ZERO_STRUCT(state->hdr);
599                 state->wait_for_hdr = false;
600
601                 subreq = tstream_readv_pdu_send(state,
602                                                 ev,
603                                                 npas->unix_stream,
604                                                 tstream_npa_readv_next_vector,
605                                                 state);
606                 if (tevent_req_nomem(subreq, req)) {
607                         goto post;
608                 }
609                 tevent_req_set_callback(subreq,
610                                         tstream_npa_readv_msg_mode_handler,
611                                         req);
612
613                 return req;
614         }
615
616         /* this can't happen */
617         tevent_req_error(req, EINVAL);
618         goto post;
619
620  post:
621         tevent_req_post(req, ev);
622         return req;
623 }
624
625 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
626 {
627         struct tevent_req *req = tevent_req_callback_data(subreq,
628                                  struct tevent_req);
629         struct tstream_npa_readv_state *state = tevent_req_data(req,
630                                         struct tstream_npa_readv_state);
631         int ret;
632         int sys_errno;
633
634         ret = tstream_readv_recv(subreq, &sys_errno);
635         TALLOC_FREE(subreq);
636         if (ret == -1) {
637                 tevent_req_error(req, sys_errno);
638                 return;
639         }
640
641         state->ret = ret;
642
643         tevent_req_done(req);
644 }
645
646 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
647                                          void *private_data,
648                                          TALLOC_CTX *mem_ctx,
649                                          struct iovec **_vector,
650                                          size_t *_count)
651 {
652         struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
653                                         struct tstream_npa_readv_state);
654         struct tstream_npa *npas = tstream_context_data(state->stream,
655                                    struct tstream_npa);
656         struct iovec *vector;
657         size_t count;
658         uint16_t msg_len;
659         size_t left;
660
661         if (state->count == 0) {
662                 *_vector = NULL;
663                 *_count = 0;
664                 return 0;
665         }
666
667         if (!state->wait_for_hdr) {
668                 /* we need to get a message header */
669                 vector = talloc_array(mem_ctx, struct iovec, 1);
670                 if (!vector) {
671                         return -1;
672                 }
673                 ZERO_STRUCT(state->hdr);
674                 vector[0].iov_base = (char *) state->hdr;
675                 vector[0].iov_len = sizeof(state->hdr);
676
677                 count = 1;
678
679                 state->wait_for_hdr = true;
680
681                 *_vector = vector;
682                 *_count = count;
683                 return 0;
684         }
685
686         /* and now fill the callers buffers and maybe the pending buffer */
687         state->wait_for_hdr = false;
688
689         msg_len = SVAL(state->hdr, 0);
690
691         if (msg_len == 0) {
692                 errno = EIO;
693                 return -1;
694         }
695
696         state->wait_for_hdr = false;
697
698         /* +1 because we may need to fill the pending buffer */
699         vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
700         if (!vector) {
701                 return -1;
702         }
703
704         count = 0;
705         left = msg_len;
706         while (left > 0 && state->count > 0) {
707                 if (left < state->vector[0].iov_len) {
708                         uint8_t *base;
709                         base = (uint8_t *)state->vector[0].iov_base;
710                         vector[count].iov_base = (char *) base;
711                         vector[count].iov_len = left;
712                         count++;
713                         base += left;
714                         state->vector[0].iov_base = (char *) base;
715                         state->vector[0].iov_len -= left;
716                         break;
717                 }
718                 vector[count] = state->vector[0];
719                 count++;
720                 left -= state->vector[0].iov_len;
721                 state->vector += 1;
722                 state->count -= 1;
723         }
724
725         if (left > 0) {
726                 /*
727                  * if the message is longer than the buffers the caller
728                  * requested, we need to consume the rest of the message
729                  * into the pending buffer, where the next readv can
730                  * be served from.
731                  */
732                 npas->pending.iov_base = talloc_array(npas, char, left);
733                 if (!npas->pending.iov_base) {
734                         return -1;
735                 }
736                 npas->pending.iov_len = left;
737
738                 vector[count] = npas->pending;
739                 count++;
740         }
741
742         state->ret += (msg_len - left);
743
744         *_vector = vector;
745         *_count = count;
746         return 0;
747 }
748
749 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
750 {
751         struct tevent_req *req = tevent_req_callback_data(subreq,
752                                  struct tevent_req);
753         int ret;
754         int sys_errno;
755
756         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
757         TALLOC_FREE(subreq);
758         if (ret == -1) {
759                 tevent_req_error(req, sys_errno);
760                 return;
761         }
762
763         /*
764          * we do not set state->ret here as ret includes the headr size.
765          * we set it in tstream_npa_readv_pdu_next_vector()
766          */
767
768         tevent_req_done(req);
769 }
770
771 static int tstream_npa_readv_recv(struct tevent_req *req,
772                                    int *perrno)
773 {
774         struct tstream_npa_readv_state *state = tevent_req_data(req,
775                                         struct tstream_npa_readv_state);
776         int ret;
777
778         ret = tsocket_simple_int_recv(req, perrno);
779         if (ret == 0) {
780                 ret = state->ret;
781         }
782
783         tevent_req_received(req);
784         return ret;
785 }
786
787 struct tstream_npa_writev_state {
788         const struct iovec *vector;
789         size_t count;
790
791         /* the header for message mode */
792         bool hdr_used;
793         uint8_t hdr[2];
794
795         int ret;
796 };
797
798 static void tstream_npa_writev_handler(struct tevent_req *subreq);
799
800 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
801                                         struct tevent_context *ev,
802                                         struct tstream_context *stream,
803                                         const struct iovec *vector,
804                                         size_t count)
805 {
806         struct tevent_req *req;
807         struct tstream_npa_writev_state *state;
808         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
809         struct tevent_req *subreq;
810         size_t msg_len;
811         size_t i;
812         struct iovec *new_vector;
813
814         req = tevent_req_create(mem_ctx, &state,
815                                 struct tstream_npa_writev_state);
816         if (!req) {
817                 return NULL;
818         }
819
820         state->ret      = 0;
821
822         if (!npas->unix_stream) {
823                 tevent_req_error(req, ENOTCONN);
824                 goto post;
825         }
826
827         switch (npas->file_type) {
828         case FILE_TYPE_BYTE_MODE_PIPE:
829                 state->hdr_used = false;
830                 state->vector   = vector;
831                 state->count    = count;
832                 break;
833
834         case FILE_TYPE_MESSAGE_MODE_PIPE:
835                 /*
836                  * we make a copy of the vector and prepend a header
837                  * with the length
838                  */
839                 new_vector      = talloc_array(state, struct iovec, count + 1);
840                 if (tevent_req_nomem(new_vector, req)) {
841                         goto post;
842                 }
843                 new_vector[0].iov_base = (char *) state->hdr;
844                 new_vector[0].iov_len = sizeof(state->hdr);
845                 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
846
847                 state->hdr_used = true;
848                 state->vector   = new_vector;
849                 state->count    = count + 1;
850
851                 msg_len = 0;
852                 for (i=0; i < count; i++) {
853                         msg_len += vector[i].iov_len;
854                 }
855
856                 if (msg_len > UINT16_MAX) {
857                         tevent_req_error(req, EMSGSIZE);
858                         goto post;
859                 }
860
861                 SSVAL(state->hdr, 0, msg_len);
862                 break;
863         }
864
865         subreq = tstream_writev_send(state,
866                                      ev,
867                                      npas->unix_stream,
868                                      state->vector,
869                                      state->count);
870         if (tevent_req_nomem(subreq, req)) {
871                 goto post;
872         }
873         tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
874
875         return req;
876
877  post:
878         tevent_req_post(req, ev);
879         return req;
880 }
881
882 static void tstream_npa_writev_handler(struct tevent_req *subreq)
883 {
884         struct tevent_req *req = tevent_req_callback_data(subreq,
885                                  struct tevent_req);
886         struct tstream_npa_writev_state *state = tevent_req_data(req,
887                                         struct tstream_npa_writev_state);
888         int ret;
889         int sys_errno;
890
891         ret = tstream_writev_recv(subreq, &sys_errno);
892         TALLOC_FREE(subreq);
893         if (ret == -1) {
894                 tevent_req_error(req, sys_errno);
895                 return;
896         }
897
898         /*
899          * in message mode we need to hide the length
900          * of the hdr from the caller
901          */
902         if (state->hdr_used) {
903                 ret -= sizeof(state->hdr);
904         }
905
906         state->ret = ret;
907
908         tevent_req_done(req);
909 }
910
911 static int tstream_npa_writev_recv(struct tevent_req *req,
912                                    int *perrno)
913 {
914         struct tstream_npa_writev_state *state = tevent_req_data(req,
915                                         struct tstream_npa_writev_state);
916         int ret;
917
918         ret = tsocket_simple_int_recv(req, perrno);
919         if (ret == 0) {
920                 ret = state->ret;
921         }
922
923         tevent_req_received(req);
924         return ret;
925 }
926
927 struct tstream_npa_disconnect_state {
928         struct tstream_context *stream;
929 };
930
931 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
932
933 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
934                                                 struct tevent_context *ev,
935                                                 struct tstream_context *stream)
936 {
937         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
938         struct tevent_req *req;
939         struct tstream_npa_disconnect_state *state;
940         struct tevent_req *subreq;
941
942         req = tevent_req_create(mem_ctx, &state,
943                                 struct tstream_npa_disconnect_state);
944         if (req == NULL) {
945                 return NULL;
946         }
947
948         state->stream = stream;
949
950         if (!npas->unix_stream) {
951                 tevent_req_error(req, ENOTCONN);
952                 goto post;
953         }
954
955         subreq = tstream_disconnect_send(state,
956                                          ev,
957                                          npas->unix_stream);
958         if (tevent_req_nomem(subreq, req)) {
959                 goto post;
960         }
961         tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
962
963         return req;
964
965 post:
966         tevent_req_post(req, ev);
967         return req;
968 }
969
970 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
971 {
972         struct tevent_req *req = tevent_req_callback_data(subreq,
973                                  struct tevent_req);
974         struct tstream_npa_disconnect_state *state = tevent_req_data(req,
975                                         struct tstream_npa_disconnect_state);
976         struct tstream_context *stream = state->stream;
977         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
978         int ret;
979         int sys_errno;
980
981         ret = tstream_disconnect_recv(subreq, &sys_errno);
982         TALLOC_FREE(subreq);
983         if (ret == -1) {
984                 tevent_req_error(req, sys_errno);
985                 return;
986         }
987
988         TALLOC_FREE(npas->unix_stream);
989
990         tevent_req_done(req);
991 }
992
993 static int tstream_npa_disconnect_recv(struct tevent_req *req,
994                                        int *perrno)
995 {
996         int ret;
997
998         ret = tsocket_simple_int_recv(req, perrno);
999
1000         tevent_req_received(req);
1001         return ret;
1002 }
1003
1004 static const struct tstream_context_ops tstream_npa_ops = {
1005         .name                   = "npa",
1006
1007         .pending_bytes          = tstream_npa_pending_bytes,
1008
1009         .readv_send             = tstream_npa_readv_send,
1010         .readv_recv             = tstream_npa_readv_recv,
1011
1012         .writev_send            = tstream_npa_writev_send,
1013         .writev_recv            = tstream_npa_writev_recv,
1014
1015         .disconnect_send        = tstream_npa_disconnect_send,
1016         .disconnect_recv        = tstream_npa_disconnect_recv,
1017 };
1018
1019 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1020                                  int fd,
1021                                  uint16_t file_type,
1022                                  struct tstream_context **_stream,
1023                                  const char *location)
1024 {
1025         struct tstream_context *stream;
1026         struct tstream_npa *npas;
1027         int ret;
1028
1029         switch (file_type) {
1030         case FILE_TYPE_BYTE_MODE_PIPE:
1031                 break;
1032         case FILE_TYPE_MESSAGE_MODE_PIPE:
1033                 break;
1034         default:
1035                 errno = EINVAL;
1036                 return -1;
1037         }
1038
1039         stream = tstream_context_create(mem_ctx,
1040                                         &tstream_npa_ops,
1041                                         &npas,
1042                                         struct tstream_npa,
1043                                         location);
1044         if (!stream) {
1045                 return -1;
1046         }
1047         ZERO_STRUCTP(npas);
1048
1049         npas->file_type = file_type;
1050
1051         ret = tstream_bsd_existing_socket(stream, fd,
1052                                           &npas->unix_stream);
1053         if (ret == -1) {
1054                 int saved_errno = errno;
1055                 talloc_free(stream);
1056                 errno = saved_errno;
1057                 return -1;
1058         }
1059
1060         *_stream = stream;
1061         return 0;
1062 }
1063
1064
1065 struct tstream_npa_accept_state {
1066         struct tevent_context *ev;
1067         struct tstream_context *plain;
1068         uint16_t file_type;
1069         uint16_t device_state;
1070         uint64_t alloc_size;
1071
1072         DATA_BLOB npa_blob;
1073         struct iovec out_iov;
1074
1075         /* results */
1076         NTSTATUS accept_status;
1077         struct tsocket_address *client;
1078         char *client_name;
1079         struct tsocket_address *server;
1080         char *server_name;
1081         struct auth_session_info_transport *session_info;
1082 };
1083
1084 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1085                                           void *private_data,
1086                                           TALLOC_CTX *mem_ctx,
1087                                           struct iovec **_vector,
1088                                           size_t *_count);
1089 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1090 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1091
1092 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1093                                         struct tevent_context *ev,
1094                                         struct tstream_context *plain,
1095                                         uint16_t file_type,
1096                                         uint16_t device_state,
1097                                         uint64_t allocation_size)
1098 {
1099         struct tstream_npa_accept_state *state;
1100         struct tevent_req *req, *subreq;
1101
1102         req = tevent_req_create(mem_ctx, &state,
1103                                 struct tstream_npa_accept_state);
1104         if (req == NULL) {
1105                 return NULL;
1106         }
1107
1108         switch (file_type) {
1109         case FILE_TYPE_BYTE_MODE_PIPE:
1110                 break;
1111         case FILE_TYPE_MESSAGE_MODE_PIPE:
1112                 break;
1113         default:
1114                 tevent_req_error(req, EINVAL);
1115                 goto post;
1116         }
1117
1118         ZERO_STRUCTP(state);
1119
1120         state->ev = ev;
1121         state->plain = plain;
1122         state->file_type = file_type;
1123         state->device_state = device_state;
1124         state->alloc_size = allocation_size;
1125
1126         /*
1127          * The named pipe pdu's have the length as 8 byte (initial_read_size),
1128          * named_pipe_full_request provides the pdu length then.
1129          */
1130         subreq = tstream_readv_pdu_send(state, ev, plain,
1131                                         tstream_npa_accept_next_vector,
1132                                         state);
1133         if (tevent_req_nomem(subreq, req)) {
1134                 goto post;
1135         }
1136
1137         tevent_req_set_callback(subreq,
1138                                 tstream_npa_accept_existing_reply, req);
1139
1140         return req;
1141
1142 post:
1143         tevent_req_post(req, ev);
1144         return req;
1145 }
1146
1147 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1148                                           void *private_data,
1149                                           TALLOC_CTX *mem_ctx,
1150                                           struct iovec **_vector,
1151                                           size_t *_count)
1152 {
1153         struct tstream_npa_accept_state *state =
1154                 talloc_get_type_abort(private_data,
1155                                         struct tstream_npa_accept_state);
1156         struct iovec *vector;
1157         size_t count;
1158         off_t ofs = 0;
1159
1160         if (state->npa_blob.length == 0) {
1161                 state->npa_blob = data_blob_talloc(state, NULL, 4);
1162                 if (!state->npa_blob.data) {
1163                         return -1;
1164                 }
1165         } else if (state->npa_blob.length == 4) {
1166                 uint32_t msg_len;
1167
1168                 ofs = 4;
1169
1170                 msg_len = RIVAL(state->npa_blob.data, 0);
1171
1172                 if (msg_len > 0x00FFFFFF) {
1173                         errno = EMSGSIZE;
1174                         return -1;
1175                 }
1176
1177                 if (msg_len == 0) {
1178                         errno = EMSGSIZE;
1179                         return -1;
1180                 }
1181
1182                 msg_len += ofs;
1183
1184                 state->npa_blob.data = talloc_realloc(state,
1185                                                       state->npa_blob.data,
1186                                                       uint8_t, msg_len);
1187                 if (!state->npa_blob.data) {
1188                         return -1;
1189                 }
1190                 state->npa_blob.length = msg_len;
1191         } else {
1192                 if (memcmp(&state->npa_blob.data[4],
1193                            NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1194                         DEBUG(0, ("Wrong protocol\n"));
1195 #if defined(EPROTONOSUPPORT)
1196                         errno = EPROTONOSUPPORT;
1197 #elif defined(EPROTO)
1198                         errno = EPROTO;
1199 #else
1200                         errno = EINVAL;
1201 #endif
1202                         return -1;
1203                 }
1204                 *_vector = NULL;
1205                 *_count = 0;
1206                 return 0;
1207         }
1208
1209         /* we need to get a message header */
1210         vector = talloc_array(mem_ctx, struct iovec, 1);
1211         if (!vector) {
1212                 return -1;
1213         }
1214         vector[0].iov_base = (char *) (state->npa_blob.data + ofs);
1215         vector[0].iov_len = state->npa_blob.length - ofs;
1216         count = 1;
1217
1218         *_vector = vector;
1219         *_count = count;
1220         return 0;
1221 }
1222
1223 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1224 {
1225         struct tevent_req *req =
1226                         tevent_req_callback_data(subreq, struct tevent_req);
1227         struct tstream_npa_accept_state *state =
1228                         tevent_req_data(req, struct tstream_npa_accept_state);
1229         struct named_pipe_auth_req *pipe_request;
1230         struct named_pipe_auth_rep pipe_reply;
1231         struct named_pipe_auth_req_info4 i4;
1232         enum ndr_err_code ndr_err;
1233         DATA_BLOB out;
1234         int sys_errno;
1235         int ret;
1236
1237         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1238         TALLOC_FREE(subreq);
1239         if (ret == -1) {
1240                 tevent_req_error(req, sys_errno);
1241                 return;
1242         }
1243
1244         DEBUG(10, ("Received packet of length %lu\n",
1245                    (long)state->npa_blob.length));
1246         dump_data(11, state->npa_blob.data, state->npa_blob.length);
1247
1248         ZERO_STRUCT(pipe_reply);
1249         pipe_reply.level = 0;
1250         pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1251         /*
1252          * TODO: check it's a root (uid == 0) pipe
1253          */
1254
1255         pipe_request = talloc(state, struct named_pipe_auth_req);
1256         if (!pipe_request) {
1257                 DEBUG(0, ("Out of memory!\n"));
1258                 goto reply;
1259         }
1260
1261         /* parse the passed credentials */
1262         ndr_err = ndr_pull_struct_blob_all(
1263                         &state->npa_blob, pipe_request, pipe_request,
1264                         (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1265         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1266                 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1267                 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1268                           nt_errstr(pipe_reply.status)));
1269                 goto reply;
1270         }
1271
1272         if (DEBUGLVL(10)) {
1273                 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1274         }
1275
1276         ZERO_STRUCT(i4);
1277
1278         if (pipe_request->level != 4) {
1279                 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1280                 pipe_reply.level = 0;
1281                 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1282                 goto reply;
1283         }
1284
1285         pipe_reply.level = 4;
1286         pipe_reply.status = NT_STATUS_OK;
1287         pipe_reply.info.info4.file_type = state->file_type;
1288         pipe_reply.info.info4.device_state = state->device_state;
1289         pipe_reply.info.info4.allocation_size = state->alloc_size;
1290
1291         i4 = pipe_request->info.info4;
1292         if (i4.server_addr == NULL) {
1293                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1294                 DEBUG(2, ("Missing server address\n"));
1295                 goto reply;
1296         }
1297         if (i4.client_addr == NULL) {
1298                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1299                 DEBUG(2, ("Missing client address\n"));
1300                 goto reply;
1301         }
1302
1303         state->server_name = discard_const_p(char,
1304                                              talloc_move(state, &i4.server_name));
1305         ret = tsocket_address_inet_from_strings(state, "ip",
1306                                                 i4.server_addr,
1307                                                 i4.server_port,
1308                                                 &state->server);
1309         if (ret != 0) {
1310                 DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1311                           i4.server_addr, i4.server_port,
1312                           strerror(errno)));
1313                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1314                 goto reply;
1315         }
1316
1317         state->client_name = discard_const_p(char,
1318                                              talloc_move(state, &i4.client_name));
1319         ret = tsocket_address_inet_from_strings(state, "ip",
1320                                                 i4.client_addr,
1321                                                 i4.client_port,
1322                                                 &state->client);
1323         if (ret != 0) {
1324                 DEBUG(2, ("Invalid client address[%s:%u] - %s\n",
1325                           i4.client_addr, i4.client_port,
1326                           strerror(errno)));
1327                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1328                 goto reply;
1329         }
1330
1331         state->session_info = talloc_move(state, &i4.session_info);
1332 reply:
1333         /* create the output */
1334         ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1335                         (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1336         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337                 DEBUG(2, ("Error encoding structure: %s",
1338                           ndr_map_error2string(ndr_err)));
1339                 tevent_req_error(req, EIO);
1340                 return;
1341         }
1342
1343         DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1344         dump_data(11, out.data, out.length);
1345
1346         if (DEBUGLVL(10)) {
1347                 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1348         }
1349
1350         state->accept_status = pipe_reply.status;
1351
1352         state->out_iov.iov_base = (char *) out.data;
1353         state->out_iov.iov_len = out.length;
1354
1355         subreq = tstream_writev_send(state, state->ev,
1356                                      state->plain,
1357                                      &state->out_iov, 1);
1358         if (tevent_req_nomem(subreq, req)) {
1359                 DEBUG(0, ("no memory for tstream_writev_send"));
1360                 return;
1361         }
1362
1363         tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1364 }
1365
1366 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1367 {
1368         struct tevent_req *req =
1369                         tevent_req_callback_data(subreq, struct tevent_req);
1370         int sys_errno;
1371         int ret;
1372
1373         ret = tstream_writev_recv(subreq, &sys_errno);
1374         TALLOC_FREE(subreq);
1375         if (ret == -1) {
1376                 tevent_req_error(req, sys_errno);
1377                 return;
1378         }
1379
1380         tevent_req_done(req);
1381 }
1382
1383 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1384                                       int *perrno,
1385                                       TALLOC_CTX *mem_ctx,
1386                                       struct tstream_context **stream,
1387                                       struct tsocket_address **client,
1388                                       char **_client_name,
1389                                       struct tsocket_address **server,
1390                                       char **server_name,
1391                                       struct auth_session_info_transport **session_info,
1392                                       const char *location)
1393 {
1394         struct tstream_npa_accept_state *state =
1395                         tevent_req_data(req, struct tstream_npa_accept_state);
1396         struct tstream_npa *npas;
1397         int ret;
1398
1399         ret = tsocket_simple_int_recv(req, perrno);
1400         if (ret != 0) {
1401                 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1402                           strerror(*perrno)));
1403                 tevent_req_received(req);
1404                 return -1;
1405         }
1406
1407         if (!NT_STATUS_IS_OK(state->accept_status)) {
1408 #if defined(EPROTONOSUPPORT)
1409                 *perrno = EPROTONOSUPPORT;
1410 #elif defined(EPROTO)
1411                 *perrno = EPROTO;
1412 #else
1413                 *perrno = EINVAL;
1414 #endif
1415                 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1416                           nt_errstr(state->accept_status),
1417                           strerror(*perrno)));
1418                 tevent_req_received(req);
1419                 return -1;
1420         }
1421
1422         *stream = tstream_context_create(mem_ctx,
1423                                          &tstream_npa_ops,
1424                                          &npas,
1425                                          struct tstream_npa,
1426                                          location);
1427         if (!*stream) {
1428                 *perrno = ENOMEM;
1429                 tevent_req_received(req);
1430                 return -1;
1431         }
1432         ZERO_STRUCTP(npas);
1433         npas->unix_stream = state->plain;
1434         npas->file_type = state->file_type;
1435
1436         *client = talloc_move(mem_ctx, &state->client);
1437         *_client_name = talloc_move(mem_ctx, &state->client_name);
1438         *server = talloc_move(mem_ctx, &state->server);
1439         *server_name = talloc_move(mem_ctx, &state->server_name);
1440         *session_info = talloc_move(mem_ctx, &state->session_info);
1441
1442         tevent_req_received(req);
1443         return 0;
1444 }
1445
1446
1447 /* SOCKETPAIR for internal rpc communication */
1448
1449 /* file_type is FILE_TYPE_BYTE_MODE_PIPE or FILE_TYPE_MESSAGE_MODE_PIPE */
1450 int _tstream_npa_socketpair(uint16_t file_type,
1451                             TALLOC_CTX *mem_ctx1,
1452                             struct tstream_context **pstream1,
1453                             TALLOC_CTX *mem_ctx2,
1454                             struct tstream_context **pstream2,
1455                             const char *location)
1456 {
1457         struct tstream_context *stream1 = NULL;
1458         struct tstream_context *stream2 = NULL;
1459         int fds[2];
1460         int fd1;
1461         int fd2;
1462         int rc;
1463         bool ok;
1464
1465         rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
1466         if (rc == -1) {
1467                 return -1;
1468         }
1469         fd1 = fds[0];
1470         fd2 = fds[1];
1471
1472         ok = smb_set_close_on_exec(fd1);
1473         if (!ok) {
1474                 goto close_fail;
1475         }
1476
1477         ok = smb_set_close_on_exec(fd2);
1478         if (!ok) {
1479                 goto close_fail;
1480         }
1481
1482         rc = set_blocking(fd1, false);
1483         if (rc == -1) {
1484                 goto close_fail;
1485         }
1486
1487         rc = set_blocking(fd2, false);
1488         if (rc == -1) {
1489                 goto close_fail;
1490         }
1491
1492         rc = _tstream_npa_existing_socket(mem_ctx1,
1493                                           fd1,
1494                                           file_type,
1495                                           &stream1,
1496                                           location);
1497         if (rc == -1) {
1498                 goto close_fail;
1499         }
1500
1501         rc = _tstream_npa_existing_socket(mem_ctx2,
1502                                           fd2,
1503                                           file_type,
1504                                           &stream2,
1505                                           location);
1506         if (rc == -1) {
1507                 int sys_errno = errno;
1508                 talloc_free(stream1);
1509                 close(fd2);
1510                 errno = sys_errno;
1511                 return -1;
1512         }
1513
1514         *pstream1 = stream1;
1515         *pstream2 = stream2;
1516
1517         return 0;
1518
1519 close_fail:
1520         {
1521                 int sys_errno = errno;
1522                 close(fd1);
1523                 close(fd2);
1524                 errno = sys_errno;
1525                 return -1;
1526         }
1527 }