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