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