libcli/named_pipe_auth: add tstream_npa_connect_send/recv()
[kai/samba.git] / libcli / named_pipe_auth / npa_tstream.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../util/tevent_unix.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
26 #include "../libcli/named_pipe_auth/npa_tstream.h"
27 #include "libcli/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,
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;
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
463         return ret;
464 }
465
466 struct tstream_npa_readv_state {
467         struct tstream_context *stream;
468
469         struct iovec *vector;
470         size_t count;
471
472         /* the header for message mode */
473         uint8_t hdr[2];
474         bool wait_for_hdr;
475
476         int ret;
477 };
478
479 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
480 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
481                                          void *private_data,
482                                          TALLOC_CTX *mem_ctx,
483                                          struct iovec **_vector,
484                                          size_t *_count);
485 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
486
487 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
488                                         struct tevent_context *ev,
489                                         struct tstream_context *stream,
490                                         struct iovec *vector,
491                                         size_t count)
492 {
493         struct tevent_req *req;
494         struct tstream_npa_readv_state *state;
495         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
496         struct tevent_req *subreq;
497         off_t ofs;
498         size_t left;
499         uint8_t *pbase;
500
501         req = tevent_req_create(mem_ctx, &state,
502                                 struct tstream_npa_readv_state);
503         if (!req) {
504                 return NULL;
505         }
506
507         state->stream   = stream;
508         state->ret      = 0;
509
510         if (!npas->unix_stream) {
511                 tevent_req_error(req, ENOTCONN);
512                 goto post;
513         }
514
515         switch (npas->file_type) {
516         case FILE_TYPE_BYTE_MODE_PIPE:
517                 state->vector = vector;
518                 state->count = count;
519
520                 subreq = tstream_readv_send(state,
521                                             ev,
522                                             npas->unix_stream,
523                                             state->vector,
524                                             state->count);
525                 if (tevent_req_nomem(subreq,req)) {
526                         goto post;
527                 }
528                 tevent_req_set_callback(subreq,
529                                         tstream_npa_readv_byte_mode_handler,
530                                         req);
531
532                 return req;
533
534         case FILE_TYPE_MESSAGE_MODE_PIPE:
535                 /*
536                  * we make a copy of the vector and prepend a header
537                  * with the length
538                  */
539                 state->vector   = talloc_array(state, struct iovec, count);
540                 if (tevent_req_nomem(state->vector, req)) {
541                         goto post;
542                 }
543                 memcpy(state->vector, vector, sizeof(struct iovec)*count);
544                 state->count = count;
545
546                 /*
547                  * copy the pending buffer first
548                  */
549                 ofs = 0;
550                 left = npas->pending.iov_len;
551                 pbase = (uint8_t *)npas->pending.iov_base;
552
553                 while (left > 0 && state->count > 0) {
554                         uint8_t *base;
555                         base = (uint8_t *)state->vector[0].iov_base;
556                         if (left < state->vector[0].iov_len) {
557                                 memcpy(base, pbase + ofs, left);
558
559                                 base += left;
560                                 state->vector[0].iov_base = base;
561                                 state->vector[0].iov_len -= left;
562
563                                 ofs += left;
564                                 left = 0;
565                                 TALLOC_FREE(pbase);
566                                 ZERO_STRUCT(npas->pending);
567                                 break;
568                         }
569                         memcpy(base, pbase + ofs, state->vector[0].iov_len);
570
571                         ofs += state->vector[0].iov_len;
572                         left -= state->vector[0].iov_len;
573                         state->vector += 1;
574                         state->count -= 1;
575
576                         if (left == 0) {
577                                 TALLOC_FREE(pbase);
578                                 ZERO_STRUCT(npas->pending);
579                                 break;
580                         }
581                 }
582
583                 if (left > 0) {
584                         memmove(pbase, pbase + ofs, left);
585                         npas->pending.iov_base = pbase;
586                         npas->pending.iov_len = left;
587                         /*
588                          * this cannot fail and even if it
589                          * fails we can handle it
590                          */
591                         pbase = talloc_realloc(npas, pbase, uint8_t, left);
592                         if (pbase) {
593                                 npas->pending.iov_base = pbase;
594                         }
595                         pbase = NULL;
596                 }
597
598                 state->ret += ofs;
599
600                 if (state->count == 0) {
601                         tevent_req_done(req);
602                         goto post;
603                 }
604
605                 ZERO_STRUCT(state->hdr);
606                 state->wait_for_hdr = false;
607
608                 subreq = tstream_readv_pdu_send(state,
609                                                 ev,
610                                                 npas->unix_stream,
611                                                 tstream_npa_readv_next_vector,
612                                                 state);
613                 if (tevent_req_nomem(subreq, req)) {
614                         goto post;
615                 }
616                 tevent_req_set_callback(subreq,
617                                         tstream_npa_readv_msg_mode_handler,
618                                         req);
619
620                 return req;
621         }
622
623         /* this can't happen */
624         tevent_req_error(req, EINVAL);
625         goto post;
626
627  post:
628         tevent_req_post(req, ev);
629         return req;
630 }
631
632 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
633 {
634         struct tevent_req *req = tevent_req_callback_data(subreq,
635                                  struct tevent_req);
636         struct tstream_npa_readv_state *state = tevent_req_data(req,
637                                         struct tstream_npa_readv_state);
638         int ret;
639         int sys_errno;
640
641         ret = tstream_readv_recv(subreq, &sys_errno);
642         TALLOC_FREE(subreq);
643         if (ret == -1) {
644                 tevent_req_error(req, sys_errno);
645                 return;
646         }
647
648         state->ret = ret;
649
650         tevent_req_done(req);
651 }
652
653 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
654                                          void *private_data,
655                                          TALLOC_CTX *mem_ctx,
656                                          struct iovec **_vector,
657                                          size_t *_count)
658 {
659         struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
660                                         struct tstream_npa_readv_state);
661         struct tstream_npa *npas = tstream_context_data(state->stream,
662                                    struct tstream_npa);
663         struct iovec *vector;
664         size_t count;
665         uint16_t msg_len;
666         size_t left;
667
668         if (state->count == 0) {
669                 *_vector = NULL;
670                 *_count = 0;
671                 return 0;
672         }
673
674         if (!state->wait_for_hdr) {
675                 /* we need to get a message header */
676                 vector = talloc_array(mem_ctx, struct iovec, 1);
677                 if (!vector) {
678                         return -1;
679                 }
680                 ZERO_STRUCT(state->hdr);
681                 vector[0].iov_base = state->hdr;
682                 vector[0].iov_len = sizeof(state->hdr);
683
684                 count = 1;
685
686                 state->wait_for_hdr = true;
687
688                 *_vector = vector;
689                 *_count = count;
690                 return 0;
691         }
692
693         /* and now fill the callers buffers and maybe the pending buffer */
694         state->wait_for_hdr = false;
695
696         msg_len = SVAL(state->hdr, 0);
697
698         if (msg_len == 0) {
699                 errno = EIO;
700                 return -1;
701         }
702
703         state->wait_for_hdr = false;
704
705         /* +1 because we may need to fill the pending buffer */
706         vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
707         if (!vector) {
708                 return -1;
709         }
710
711         count = 0;
712         left = msg_len;
713         while (left > 0 && state->count > 0) {
714                 if (left < state->vector[0].iov_len) {
715                         uint8_t *base;
716                         base = (uint8_t *)state->vector[0].iov_base;
717                         vector[count].iov_base = base;
718                         vector[count].iov_len = left;
719                         count++;
720                         base += left;
721                         state->vector[0].iov_base = base;
722                         state->vector[0].iov_len -= left;
723                         break;
724                 }
725                 vector[count] = state->vector[0];
726                 count++;
727                 left -= state->vector[0].iov_len;
728                 state->vector += 1;
729                 state->count -= 1;
730         }
731
732         if (left > 0) {
733                 /*
734                  * if the message if longer than the buffers the caller
735                  * requested, we need to consume the rest of the message
736                  * into the pending buffer, where the next readv can
737                  * be served from.
738                  */
739                 npas->pending.iov_base = talloc_array(npas, uint8_t, left);
740                 if (!npas->pending.iov_base) {
741                         return -1;
742                 }
743                 npas->pending.iov_len = left;
744
745                 vector[count] = npas->pending;
746                 count++;
747         }
748
749         state->ret += (msg_len - left);
750
751         *_vector = vector;
752         *_count = count;
753         return 0;
754 }
755
756 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
757 {
758         struct tevent_req *req = tevent_req_callback_data(subreq,
759                                  struct tevent_req);
760         int ret;
761         int sys_errno;
762
763         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
764         TALLOC_FREE(subreq);
765         if (ret == -1) {
766                 tevent_req_error(req, sys_errno);
767                 return;
768         }
769
770         /*
771          * we do not set state->ret here as ret includes the headr size.
772          * we set it in tstream_npa_readv_pdu_next_vector()
773          */
774
775         tevent_req_done(req);
776 }
777
778 static int tstream_npa_readv_recv(struct tevent_req *req,
779                                    int *perrno)
780 {
781         struct tstream_npa_readv_state *state = tevent_req_data(req,
782                                         struct tstream_npa_readv_state);
783         int ret;
784
785         ret = tsocket_simple_int_recv(req, perrno);
786         if (ret == 0) {
787                 ret = state->ret;
788         }
789
790         tevent_req_received(req);
791         return ret;
792 }
793
794 struct tstream_npa_writev_state {
795         const struct iovec *vector;
796         size_t count;
797
798         /* the header for message mode */
799         uint8_t hdr[2];
800
801         int ret;
802 };
803
804 static void tstream_npa_writev_handler(struct tevent_req *subreq);
805
806 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
807                                         struct tevent_context *ev,
808                                         struct tstream_context *stream,
809                                         const struct iovec *vector,
810                                         size_t count)
811 {
812         struct tevent_req *req;
813         struct tstream_npa_writev_state *state;
814         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
815         struct tevent_req *subreq;
816         size_t msg_len;
817         size_t i;
818         struct iovec *new_vector;
819
820         req = tevent_req_create(mem_ctx, &state,
821                                 struct tstream_npa_writev_state);
822         if (!req) {
823                 return NULL;
824         }
825
826         state->ret      = 0;
827
828         if (!npas->unix_stream) {
829                 tevent_req_error(req, ENOTCONN);
830                 goto post;
831         }
832
833         switch (npas->file_type) {
834         case FILE_TYPE_BYTE_MODE_PIPE:
835                 state->vector   = vector;
836                 state->count    = count;
837                 break;
838
839         case FILE_TYPE_MESSAGE_MODE_PIPE:
840                 /*
841                  * we make a copy of the vector and prepend a header
842                  * with the length
843                  */
844                 new_vector      = talloc_array(state, struct iovec, count + 1);
845                 if (tevent_req_nomem(new_vector, req)) {
846                         goto post;
847                 }
848                 new_vector[0].iov_base = state->hdr;
849                 new_vector[0].iov_len = sizeof(state->hdr);
850                 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
851
852                 state->vector   = new_vector;
853                 state->count    = count + 1;
854
855                 msg_len = 0;
856                 for (i=0; i < count; i++) {
857                         msg_len += vector[i].iov_len;
858                 }
859
860                 if (msg_len > UINT16_MAX) {
861                         tevent_req_error(req, EMSGSIZE);
862                         goto post;
863                 }
864
865                 SSVAL(state->hdr, 0, msg_len);
866                 break;
867         }
868
869         subreq = tstream_writev_send(state,
870                                      ev,
871                                      npas->unix_stream,
872                                      state->vector,
873                                      state->count);
874         if (tevent_req_nomem(subreq, req)) {
875                 goto post;
876         }
877         tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
878
879         return req;
880
881  post:
882         tevent_req_post(req, ev);
883         return req;
884 }
885
886 static void tstream_npa_writev_handler(struct tevent_req *subreq)
887 {
888         struct tevent_req *req = tevent_req_callback_data(subreq,
889                                  struct tevent_req);
890         struct tstream_npa_writev_state *state = tevent_req_data(req,
891                                         struct tstream_npa_writev_state);
892         int ret;
893         int sys_errno;
894
895         ret = tstream_writev_recv(subreq, &sys_errno);
896         TALLOC_FREE(subreq);
897         if (ret == -1) {
898                 tevent_req_error(req, sys_errno);
899                 return;
900         }
901
902         state->ret = ret;
903
904         tevent_req_done(req);
905 }
906
907 static int tstream_npa_writev_recv(struct tevent_req *req,
908                                    int *perrno)
909 {
910         struct tstream_npa_writev_state *state = tevent_req_data(req,
911                                         struct tstream_npa_writev_state);
912         int ret;
913
914         ret = tsocket_simple_int_recv(req, perrno);
915         if (ret == 0) {
916                 ret = state->ret;
917         }
918
919         tevent_req_received(req);
920         return ret;
921 }
922
923 struct tstream_npa_disconnect_state {
924         struct tstream_context *stream;
925 };
926
927 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
928
929 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
930                                                 struct tevent_context *ev,
931                                                 struct tstream_context *stream)
932 {
933         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
934         struct tevent_req *req;
935         struct tstream_npa_disconnect_state *state;
936         struct tevent_req *subreq;
937
938         req = tevent_req_create(mem_ctx, &state,
939                                 struct tstream_npa_disconnect_state);
940         if (req == NULL) {
941                 return NULL;
942         }
943
944         state->stream = stream;
945
946         if (!npas->unix_stream) {
947                 tevent_req_error(req, ENOTCONN);
948                 goto post;
949         }
950
951         subreq = tstream_disconnect_send(state,
952                                          ev,
953                                          npas->unix_stream);
954         if (tevent_req_nomem(subreq, req)) {
955                 goto post;
956         }
957         tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
958
959         return req;
960
961 post:
962         tevent_req_post(req, ev);
963         return req;
964 }
965
966 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
967 {
968         struct tevent_req *req = tevent_req_callback_data(subreq,
969                                  struct tevent_req);
970         struct tstream_npa_disconnect_state *state = tevent_req_data(req,
971                                         struct tstream_npa_disconnect_state);
972         struct tstream_context *stream = state->stream;
973         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
974         int ret;
975         int sys_errno;
976
977         ret = tstream_disconnect_recv(subreq, &sys_errno);
978         TALLOC_FREE(subreq);
979         if (ret == -1) {
980                 tevent_req_error(req, sys_errno);
981                 return;
982         }
983
984         TALLOC_FREE(npas->unix_stream);
985
986         tevent_req_done(req);
987 }
988
989 static int tstream_npa_disconnect_recv(struct tevent_req *req,
990                                        int *perrno)
991 {
992         int ret;
993
994         ret = tsocket_simple_int_recv(req, perrno);
995
996         tevent_req_received(req);
997         return ret;
998 }
999
1000 static const struct tstream_context_ops tstream_npa_ops = {
1001         .name                   = "npa",
1002
1003         .pending_bytes          = tstream_npa_pending_bytes,
1004
1005         .readv_send             = tstream_npa_readv_send,
1006         .readv_recv             = tstream_npa_readv_recv,
1007
1008         .writev_send            = tstream_npa_writev_send,
1009         .writev_recv            = tstream_npa_writev_recv,
1010
1011         .disconnect_send        = tstream_npa_disconnect_send,
1012         .disconnect_recv        = tstream_npa_disconnect_recv,
1013 };
1014
1015 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1016                                  int fd,
1017                                  uint16_t file_type,
1018                                  struct tstream_context **_stream,
1019                                  const char *location)
1020 {
1021         struct tstream_context *stream;
1022         struct tstream_npa *npas;
1023         int ret;
1024
1025         switch (file_type) {
1026         case FILE_TYPE_BYTE_MODE_PIPE:
1027                 break;
1028         case FILE_TYPE_MESSAGE_MODE_PIPE:
1029                 break;
1030         default:
1031                 errno = EINVAL;
1032                 return -1;
1033         }
1034
1035         stream = tstream_context_create(mem_ctx,
1036                                         &tstream_npa_ops,
1037                                         &npas,
1038                                         struct tstream_npa,
1039                                         location);
1040         if (!stream) {
1041                 return -1;
1042         }
1043         ZERO_STRUCTP(npas);
1044
1045         npas->file_type = file_type;
1046
1047         ret = tstream_bsd_existing_socket(stream, fd,
1048                                           &npas->unix_stream);
1049         if (ret == -1) {
1050                 int saved_errno = errno;
1051                 talloc_free(stream);
1052                 errno = saved_errno;
1053                 return -1;
1054         }
1055
1056         *_stream = stream;
1057         return 0;
1058 }
1059