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