Fix spelling s/conection/connection/
[metze/samba/wip.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 *remote_client_addr,
64                                             const char *remote_client_name_in,
65                                             const struct tsocket_address *local_server_addr,
66                                             const char *local_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 (!local_server_addr) {
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->remote_client_name = remote_client_name_in;
125         info4->remote_client_addr = tsocket_address_inet_addr_string(remote_client_addr,
126                                                                      state);
127         if (!info4->remote_client_addr) {
128                 /* errno might be EINVAL */
129                 tevent_req_error(req, errno);
130                 goto post;
131         }
132         info4->remote_client_port = tsocket_address_inet_port(remote_client_addr);
133         if (!info4->remote_client_name) {
134                 info4->remote_client_name = info4->remote_client_addr;
135         }
136
137         info4->local_server_addr = tsocket_address_inet_addr_string(local_server_addr,
138                                                                     state);
139         if (!info4->local_server_addr) {
140                 /* errno might be EINVAL */
141                 tevent_req_error(req, errno);
142                 goto post;
143         }
144         info4->local_server_port = tsocket_address_inet_port(local_server_addr);
145         if (!info4->local_server_name) {
146                 info4->local_server_name = info4->local_server_addr;
147         }
148
149         info4->session_info = discard_const_p(struct auth_session_info_transport, session_info);
150
151         if (DEBUGLVL(10)) {
152                 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
153         }
154
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;
161         }
162
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;
165
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;
172         }
173         tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
174
175         return req;
176
177 post:
178         tevent_req_post(req, ev);
179         return req;
180 }
181
182 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
183
184 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
185 {
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;
194
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;
201         }
202
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;
209         }
210         tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
211 }
212
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);
219
220 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
221 {
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;
230
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;
236         }
237
238         state->auth_rep_blob = data_blob_const(NULL, 0);
239
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;
246         }
247         tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
248 }
249
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)
255 {
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;
261
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;
266                 }
267         } else if (state->auth_rep_blob.length == 4) {
268                 uint32_t msg_len;
269
270                 ofs = 4;
271
272                 msg_len = RIVAL(state->auth_rep_blob.data, 0);
273
274                 if (msg_len > 0x00FFFFFF) {
275                         errno = EMSGSIZE;
276                         return -1;
277                 }
278
279                 if (msg_len == 0) {
280                         errno = EMSGSIZE;
281                         return -1;
282                 }
283
284                 msg_len += ofs;
285
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;
291                 }
292                 state->auth_rep_blob.length = msg_len;
293         } else {
294                 *_vector = NULL;
295                 *_count = 0;
296                 return 0;
297         }
298
299         /* we need to get a message header */
300         vector = talloc_array(mem_ctx, struct iovec, 1);
301         if (!vector) {
302                 return -1;
303         }
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;
307
308         *_vector = vector;
309         *_count = count;
310         return 0;
311 }
312
313 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
314 {
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;
324
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;
330         }
331
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);
335
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);
340
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;
346         }
347
348         if (DEBUGLVL(10)) {
349                 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
350         }
351
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;
357         }
358
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;
364         }
365
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;
371         }
372
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;
378         }
379
380         tevent_req_done(req);
381 }
382
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)
391 {
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;
399
400         if (tevent_req_is_unix_error(req, perrno)) {
401                 tevent_req_received(req);
402                 return -1;
403         }
404
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;
414         }
415         ZERO_STRUCTP(npas);
416
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;
424         }
425
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;
432 }
433
434 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
435 {
436         struct tstream_npa *npas = tstream_context_data(stream,
437                                    struct tstream_npa);
438         ssize_t ret;
439
440         if (!npas->unix_stream) {
441                 errno = ENOTCONN;
442                 return -1;
443         }
444
445         switch (npas->file_type) {
446         case FILE_TYPE_BYTE_MODE_PIPE:
447                 ret = tstream_pending_bytes(npas->unix_stream);
448                 break;
449
450         case FILE_TYPE_MESSAGE_MODE_PIPE:
451                 ret = npas->pending.iov_len;
452                 break;
453
454         default:
455                 ret = -1;
456         }
457
458         return ret;
459 }
460
461 struct tstream_npa_readv_state {
462         struct tstream_context *stream;
463
464         struct iovec *vector;
465         size_t count;
466
467         /* the header for message mode */
468         uint8_t hdr[2];
469         bool wait_for_hdr;
470
471         int ret;
472 };
473
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);
481
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)
487 {
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;
495
496         req = tevent_req_create(mem_ctx, &state,
497                                 struct tstream_npa_readv_state);
498         if (!req) {
499                 return NULL;
500         }
501
502         state->stream   = stream;
503         state->ret      = 0;
504
505         if (!npas->unix_stream) {
506                 tevent_req_error(req, ENOTCONN);
507                 goto post;
508         }
509
510         switch (npas->file_type) {
511         case FILE_TYPE_BYTE_MODE_PIPE:
512                 state->vector = vector;
513                 state->count = count;
514
515                 subreq = tstream_readv_send(state,
516                                             ev,
517                                             npas->unix_stream,
518                                             state->vector,
519                                             state->count);
520                 if (tevent_req_nomem(subreq,req)) {
521                         goto post;
522                 }
523                 tevent_req_set_callback(subreq,
524                                         tstream_npa_readv_byte_mode_handler,
525                                         req);
526
527                 return req;
528
529         case FILE_TYPE_MESSAGE_MODE_PIPE:
530                 /*
531                  * we make a copy of the vector and prepend a header
532                  * with the length
533                  */
534                 state->vector   = talloc_array(state, struct iovec, count);
535                 if (tevent_req_nomem(state->vector, req)) {
536                         goto post;
537                 }
538                 memcpy(state->vector, vector, sizeof(struct iovec)*count);
539                 state->count = count;
540
541                 /*
542                  * copy the pending buffer first
543                  */
544                 ofs = 0;
545                 left = npas->pending.iov_len;
546                 pbase = (uint8_t *)npas->pending.iov_base;
547
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);
553
554                                 base += left;
555                                 state->vector[0].iov_base = (char *) base;
556                                 state->vector[0].iov_len -= left;
557
558                                 ofs += left;
559                                 left = 0;
560                                 TALLOC_FREE(pbase);
561                                 ZERO_STRUCT(npas->pending);
562                                 break;
563                         }
564                         memcpy(base, pbase + ofs, state->vector[0].iov_len);
565
566                         ofs += state->vector[0].iov_len;
567                         left -= state->vector[0].iov_len;
568                         state->vector += 1;
569                         state->count -= 1;
570
571                         if (left == 0) {
572                                 TALLOC_FREE(pbase);
573                                 ZERO_STRUCT(npas->pending);
574                                 break;
575                         }
576                 }
577
578                 if (left > 0) {
579                         memmove(pbase, pbase + ofs, left);
580                         npas->pending.iov_base = (char *) pbase;
581                         npas->pending.iov_len = left;
582                         /*
583                          * this cannot fail and even if it
584                          * fails we can handle it
585                          */
586                         pbase = talloc_realloc(npas, pbase, uint8_t, left);
587                         if (pbase) {
588                                 npas->pending.iov_base = (char *) pbase;
589                         }
590                         pbase = NULL;
591                 }
592
593                 state->ret += ofs;
594
595                 if (state->count == 0) {
596                         tevent_req_done(req);
597                         goto post;
598                 }
599
600                 ZERO_STRUCT(state->hdr);
601                 state->wait_for_hdr = false;
602
603                 subreq = tstream_readv_pdu_send(state,
604                                                 ev,
605                                                 npas->unix_stream,
606                                                 tstream_npa_readv_next_vector,
607                                                 state);
608                 if (tevent_req_nomem(subreq, req)) {
609                         goto post;
610                 }
611                 tevent_req_set_callback(subreq,
612                                         tstream_npa_readv_msg_mode_handler,
613                                         req);
614
615                 return req;
616         }
617
618         /* this can't happen */
619         tevent_req_error(req, EINVAL);
620         goto post;
621
622  post:
623         tevent_req_post(req, ev);
624         return req;
625 }
626
627 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
628 {
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;
635
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;
641         }
642
643         state->ret = ret;
644
645         tevent_req_done(req);
646 }
647
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)
653 {
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;
662
663         if (state->count == 0) {
664                 *_vector = NULL;
665                 *_count = 0;
666                 return 0;
667         }
668
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;
674                 }
675                 ZERO_STRUCT(state->hdr);
676                 vector[0].iov_base = (char *) state->hdr;
677                 vector[0].iov_len = sizeof(state->hdr);
678
679                 count = 1;
680
681                 state->wait_for_hdr = true;
682
683                 *_vector = vector;
684                 *_count = count;
685                 return 0;
686         }
687
688         /* and now fill the callers buffers and maybe the pending buffer */
689         state->wait_for_hdr = false;
690
691         msg_len = SVAL(state->hdr, 0);
692
693         if (msg_len == 0) {
694                 errno = EIO;
695                 return -1;
696         }
697
698         state->wait_for_hdr = false;
699
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;
704         }
705
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;
719                 }
720                 vector[count] = state->vector[0];
721                 count++;
722                 left -= state->vector[0].iov_len;
723                 state->vector += 1;
724                 state->count -= 1;
725         }
726
727         if (left > 0) {
728                 /*
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.
733                  */
734                 npas->pending.iov_base = talloc_array(npas, char, left);
735                 if (!npas->pending.iov_base) {
736                         return -1;
737                 }
738                 npas->pending.iov_len = left;
739
740                 vector[count] = npas->pending;
741                 count++;
742         }
743
744         state->ret += (msg_len - left);
745
746         *_vector = vector;
747         *_count = count;
748         return 0;
749 }
750
751 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
752 {
753         struct tevent_req *req = tevent_req_callback_data(subreq,
754                                  struct tevent_req);
755         int ret;
756         int sys_errno;
757
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;
763         }
764
765         /*
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()
768          */
769
770         tevent_req_done(req);
771 }
772
773 static int tstream_npa_readv_recv(struct tevent_req *req,
774                                    int *perrno)
775 {
776         struct tstream_npa_readv_state *state = tevent_req_data(req,
777                                         struct tstream_npa_readv_state);
778         int ret;
779
780         ret = tsocket_simple_int_recv(req, perrno);
781         if (ret == 0) {
782                 ret = state->ret;
783         }
784
785         tevent_req_received(req);
786         return ret;
787 }
788
789 struct tstream_npa_writev_state {
790         const struct iovec *vector;
791         size_t count;
792
793         /* the header for message mode */
794         bool hdr_used;
795         uint8_t hdr[2];
796
797         int ret;
798 };
799
800 static void tstream_npa_writev_handler(struct tevent_req *subreq);
801
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)
807 {
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;
815
816         req = tevent_req_create(mem_ctx, &state,
817                                 struct tstream_npa_writev_state);
818         if (!req) {
819                 return NULL;
820         }
821
822         state->ret      = 0;
823
824         if (!npas->unix_stream) {
825                 tevent_req_error(req, ENOTCONN);
826                 goto post;
827         }
828
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;
835
836         case FILE_TYPE_MESSAGE_MODE_PIPE:
837                 /*
838                  * we make a copy of the vector and prepend a header
839                  * with the length
840                  */
841                 new_vector      = talloc_array(state, struct iovec, count + 1);
842                 if (tevent_req_nomem(new_vector, req)) {
843                         goto post;
844                 }
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);
848
849                 state->hdr_used = true;
850                 state->vector   = new_vector;
851                 state->count    = count + 1;
852
853                 msg_len = 0;
854                 for (i=0; i < count; i++) {
855                         msg_len += vector[i].iov_len;
856                 }
857
858                 if (msg_len > UINT16_MAX) {
859                         tevent_req_error(req, EMSGSIZE);
860                         goto post;
861                 }
862
863                 SSVAL(state->hdr, 0, msg_len);
864                 break;
865         }
866
867         subreq = tstream_writev_send(state,
868                                      ev,
869                                      npas->unix_stream,
870                                      state->vector,
871                                      state->count);
872         if (tevent_req_nomem(subreq, req)) {
873                 goto post;
874         }
875         tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
876
877         return req;
878
879  post:
880         tevent_req_post(req, ev);
881         return req;
882 }
883
884 static void tstream_npa_writev_handler(struct tevent_req *subreq)
885 {
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;
892
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;
898         }
899
900         /*
901          * in message mode we need to hide the length
902          * of the hdr from the caller
903          */
904         if (state->hdr_used) {
905                 ret -= sizeof(state->hdr);
906         }
907
908         state->ret = ret;
909
910         tevent_req_done(req);
911 }
912
913 static int tstream_npa_writev_recv(struct tevent_req *req,
914                                    int *perrno)
915 {
916         struct tstream_npa_writev_state *state = tevent_req_data(req,
917                                         struct tstream_npa_writev_state);
918         int ret;
919
920         ret = tsocket_simple_int_recv(req, perrno);
921         if (ret == 0) {
922                 ret = state->ret;
923         }
924
925         tevent_req_received(req);
926         return ret;
927 }
928
929 struct tstream_npa_disconnect_state {
930         struct tstream_context *stream;
931 };
932
933 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
934
935 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
936                                                 struct tevent_context *ev,
937                                                 struct tstream_context *stream)
938 {
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;
943
944         req = tevent_req_create(mem_ctx, &state,
945                                 struct tstream_npa_disconnect_state);
946         if (req == NULL) {
947                 return NULL;
948         }
949
950         state->stream = stream;
951
952         if (!npas->unix_stream) {
953                 tevent_req_error(req, ENOTCONN);
954                 goto post;
955         }
956
957         subreq = tstream_disconnect_send(state,
958                                          ev,
959                                          npas->unix_stream);
960         if (tevent_req_nomem(subreq, req)) {
961                 goto post;
962         }
963         tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
964
965         return req;
966
967 post:
968         tevent_req_post(req, ev);
969         return req;
970 }
971
972 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
973 {
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;
982
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;
988         }
989
990         TALLOC_FREE(npas->unix_stream);
991
992         tevent_req_done(req);
993 }
994
995 static int tstream_npa_disconnect_recv(struct tevent_req *req,
996                                        int *perrno)
997 {
998         int ret;
999
1000         ret = tsocket_simple_int_recv(req, perrno);
1001
1002         tevent_req_received(req);
1003         return ret;
1004 }
1005
1006 static const struct tstream_context_ops tstream_npa_ops = {
1007         .name                   = "npa",
1008
1009         .pending_bytes          = tstream_npa_pending_bytes,
1010
1011         .readv_send             = tstream_npa_readv_send,
1012         .readv_recv             = tstream_npa_readv_recv,
1013
1014         .writev_send            = tstream_npa_writev_send,
1015         .writev_recv            = tstream_npa_writev_recv,
1016
1017         .disconnect_send        = tstream_npa_disconnect_send,
1018         .disconnect_recv        = tstream_npa_disconnect_recv,
1019 };
1020
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)
1026 {
1027         struct tstream_context *stream;
1028         struct tstream_npa *npas;
1029         int ret;
1030
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;
1039         }
1040
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;
1048         }
1049         ZERO_STRUCTP(npas);
1050
1051         npas->file_type = file_type;
1052
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;
1060         }
1061
1062         *_stream = stream;
1063         return 0;
1064 }
1065
1066
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;
1073
1074         DATA_BLOB npa_blob;
1075         struct iovec out_iov;
1076
1077         /* results */
1078         NTSTATUS accept_status;
1079         struct tsocket_address *remote_client_addr;
1080         char *remote_client_name;
1081         struct tsocket_address *local_server_addr;
1082         char *local_server_name;
1083         struct auth_session_info_transport *session_info;
1084 };
1085
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);
1093
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)
1100 {
1101         struct tstream_npa_accept_state *state;
1102         struct tevent_req *req, *subreq;
1103
1104         req = tevent_req_create(mem_ctx, &state,
1105                                 struct tstream_npa_accept_state);
1106         if (req == NULL) {
1107                 return NULL;
1108         }
1109
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;
1118         }
1119
1120         ZERO_STRUCTP(state);
1121
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;
1127
1128         /*
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.
1131          */
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;
1137         }
1138
1139         tevent_req_set_callback(subreq,
1140                                 tstream_npa_accept_existing_reply, req);
1141
1142         return req;
1143
1144 post:
1145         tevent_req_post(req, ev);
1146         return req;
1147 }
1148
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)
1154 {
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;
1161
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;
1166                 }
1167         } else if (state->npa_blob.length == 4) {
1168                 uint32_t msg_len;
1169
1170                 ofs = 4;
1171
1172                 msg_len = RIVAL(state->npa_blob.data, 0);
1173
1174                 if (msg_len > 0x00FFFFFF) {
1175                         errno = EMSGSIZE;
1176                         return -1;
1177                 }
1178
1179                 if (msg_len == 0) {
1180                         errno = EMSGSIZE;
1181                         return -1;
1182                 }
1183
1184                 msg_len += ofs;
1185
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;
1191                 }
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;
1205                 }
1206                 *_vector = NULL;
1207                 *_count = 0;
1208                 return 0;
1209         }
1210
1211         /* we need to get a message header */
1212         vector = talloc_array(mem_ctx, struct iovec, 1);
1213         if (!vector) {
1214                 return -1;
1215         }
1216         vector[0].iov_base = (char *) (state->npa_blob.data + ofs);
1217         vector[0].iov_len = state->npa_blob.length - ofs;
1218         count = 1;
1219
1220         *_vector = vector;
1221         *_count = count;
1222         return 0;
1223 }
1224
1225 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1226 {
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;
1238
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;
1244         }
1245
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);
1249
1250         ZERO_STRUCT(pipe_reply);
1251         pipe_reply.level = 0;
1252         pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1253         /*
1254          * TODO: check it's a root (uid == 0) pipe
1255          */
1256
1257         pipe_request = talloc(state, struct named_pipe_auth_req);
1258         if (!pipe_request) {
1259                 DEBUG(0, ("Out of memory!\n"));
1260                 goto reply;
1261         }
1262
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;
1272         }
1273
1274         if (DEBUGLVL(10)) {
1275                 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1276         }
1277
1278         ZERO_STRUCT(i4);
1279
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;
1285         }
1286
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;
1292
1293         i4 = pipe_request->info.info4;
1294         if (i4.local_server_addr == NULL) {
1295                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1296                 DEBUG(2, ("Missing local server address\n"));
1297                 goto reply;
1298         }
1299         if (i4.remote_client_addr == NULL) {
1300                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1301                 DEBUG(2, ("Missing remote client address\n"));
1302                 goto reply;
1303         }
1304
1305         state->local_server_name = discard_const_p(char,
1306                                                    talloc_move(state,
1307                                                                &i4.local_server_name));
1308         ret = tsocket_address_inet_from_strings(state, "ip",
1309                                                 i4.local_server_addr,
1310                                                 i4.local_server_port,
1311                                                 &state->local_server_addr);
1312         if (ret != 0) {
1313                 DEBUG(2, ("Invalid local server address[%s:%u] - %s\n",
1314                           i4.local_server_addr, i4.local_server_port,
1315                           strerror(errno)));
1316                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1317                 goto reply;
1318         }
1319
1320         state->remote_client_name = discard_const_p(char,
1321                                                     talloc_move(state,
1322                                                                 &i4.remote_client_name));
1323         ret = tsocket_address_inet_from_strings(state, "ip",
1324                                                 i4.remote_client_addr,
1325                                                 i4.remote_client_port,
1326                                                 &state->remote_client_addr);
1327         if (ret != 0) {
1328                 DEBUG(2, ("Invalid remote client address[%s:%u] - %s\n",
1329                           i4.remote_client_addr, i4.remote_client_port,
1330                           strerror(errno)));
1331                 pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1332                 goto reply;
1333         }
1334
1335         state->session_info = talloc_move(state, &i4.session_info);
1336 reply:
1337         /* create the output */
1338         ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1339                         (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1340         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1341                 DEBUG(2, ("Error encoding structure: %s",
1342                           ndr_map_error2string(ndr_err)));
1343                 tevent_req_error(req, EIO);
1344                 return;
1345         }
1346
1347         DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1348         dump_data(11, out.data, out.length);
1349
1350         if (DEBUGLVL(10)) {
1351                 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1352         }
1353
1354         state->accept_status = pipe_reply.status;
1355
1356         state->out_iov.iov_base = (char *) out.data;
1357         state->out_iov.iov_len = out.length;
1358
1359         subreq = tstream_writev_send(state, state->ev,
1360                                      state->plain,
1361                                      &state->out_iov, 1);
1362         if (tevent_req_nomem(subreq, req)) {
1363                 DEBUG(0, ("no memory for tstream_writev_send"));
1364                 return;
1365         }
1366
1367         tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1368 }
1369
1370 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1371 {
1372         struct tevent_req *req =
1373                         tevent_req_callback_data(subreq, struct tevent_req);
1374         int sys_errno;
1375         int ret;
1376
1377         ret = tstream_writev_recv(subreq, &sys_errno);
1378         TALLOC_FREE(subreq);
1379         if (ret == -1) {
1380                 tevent_req_error(req, sys_errno);
1381                 return;
1382         }
1383
1384         tevent_req_done(req);
1385 }
1386
1387 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1388                                       int *perrno,
1389                                       TALLOC_CTX *mem_ctx,
1390                                       struct tstream_context **stream,
1391                                       struct tsocket_address **remote_client_addr,
1392                                       char **_remote_client_name,
1393                                       struct tsocket_address **local_server_addr,
1394                                       char **local_server_name,
1395                                       struct auth_session_info_transport **session_info,
1396                                       const char *location)
1397 {
1398         struct tstream_npa_accept_state *state =
1399                         tevent_req_data(req, struct tstream_npa_accept_state);
1400         struct tstream_npa *npas;
1401         int ret;
1402
1403         ret = tsocket_simple_int_recv(req, perrno);
1404         if (ret != 0) {
1405                 DEBUG(2, ("Failed to accept named pipe connection: %s\n",
1406                           strerror(*perrno)));
1407                 tevent_req_received(req);
1408                 return -1;
1409         }
1410
1411         if (!NT_STATUS_IS_OK(state->accept_status)) {
1412 #if defined(EPROTONOSUPPORT)
1413                 *perrno = EPROTONOSUPPORT;
1414 #elif defined(EPROTO)
1415                 *perrno = EPROTO;
1416 #else
1417                 *perrno = EINVAL;
1418 #endif
1419                 DEBUG(2, ("Failed to accept named pipe connection: %s => %s\n",
1420                           nt_errstr(state->accept_status),
1421                           strerror(*perrno)));
1422                 tevent_req_received(req);
1423                 return -1;
1424         }
1425
1426         *stream = tstream_context_create(mem_ctx,
1427                                          &tstream_npa_ops,
1428                                          &npas,
1429                                          struct tstream_npa,
1430                                          location);
1431         if (!*stream) {
1432                 *perrno = ENOMEM;
1433                 tevent_req_received(req);
1434                 return -1;
1435         }
1436         ZERO_STRUCTP(npas);
1437         npas->unix_stream = state->plain;
1438         npas->file_type = state->file_type;
1439
1440         *remote_client_addr = talloc_move(mem_ctx, &state->remote_client_addr);
1441         *_remote_client_name = talloc_move(mem_ctx, &state->remote_client_name);
1442         *local_server_addr = talloc_move(mem_ctx, &state->local_server_addr);
1443         *local_server_name = talloc_move(mem_ctx, &state->local_server_name);
1444         *session_info = talloc_move(mem_ctx, &state->session_info);
1445
1446         tevent_req_received(req);
1447         return 0;
1448 }
1449
1450
1451 /* SOCKETPAIR for internal rpc communication */
1452
1453 /* file_type is FILE_TYPE_BYTE_MODE_PIPE or FILE_TYPE_MESSAGE_MODE_PIPE */
1454 int _tstream_npa_socketpair(uint16_t file_type,
1455                             TALLOC_CTX *mem_ctx1,
1456                             struct tstream_context **pstream1,
1457                             TALLOC_CTX *mem_ctx2,
1458                             struct tstream_context **pstream2,
1459                             const char *location)
1460 {
1461         struct tstream_context *stream1 = NULL;
1462         struct tstream_context *stream2 = NULL;
1463         int fds[2];
1464         int fd1;
1465         int fd2;
1466         int rc;
1467         bool ok;
1468
1469         rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
1470         if (rc == -1) {
1471                 return -1;
1472         }
1473         fd1 = fds[0];
1474         fd2 = fds[1];
1475
1476         ok = smb_set_close_on_exec(fd1);
1477         if (!ok) {
1478                 goto close_fail;
1479         }
1480
1481         ok = smb_set_close_on_exec(fd2);
1482         if (!ok) {
1483                 goto close_fail;
1484         }
1485
1486         rc = set_blocking(fd1, false);
1487         if (rc == -1) {
1488                 goto close_fail;
1489         }
1490
1491         rc = set_blocking(fd2, false);
1492         if (rc == -1) {
1493                 goto close_fail;
1494         }
1495
1496         rc = _tstream_npa_existing_socket(mem_ctx1,
1497                                           fd1,
1498                                           file_type,
1499                                           &stream1,
1500                                           location);
1501         if (rc == -1) {
1502                 goto close_fail;
1503         }
1504
1505         rc = _tstream_npa_existing_socket(mem_ctx2,
1506                                           fd2,
1507                                           file_type,
1508                                           &stream2,
1509                                           location);
1510         if (rc == -1) {
1511                 int sys_errno = errno;
1512                 talloc_free(stream1);
1513                 close(fd2);
1514                 errno = sys_errno;
1515                 return -1;
1516         }
1517
1518         *pstream1 = stream1;
1519         *pstream2 = stream2;
1520
1521         return 0;
1522
1523 close_fail:
1524         {
1525                 int sys_errno = errno;
1526                 close(fd1);
1527                 close(fd2);
1528                 errno = sys_errno;
1529                 return -1;
1530         }
1531 }