libcli/named_pipe_auth: fix error handling in _tstream_npa_connect_recv()
[metze/samba/wip.git] / libcli / named_pipe_auth / npa_tstream.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../util/tevent_unix.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "../librpc/gen_ndr/ndr_named_pipe_auth.h"
26 #include "../libcli/named_pipe_auth/npa_tstream.h"
27 #include "libcli/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         char *lower_case_npipe;
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
86         lower_case_npipe = strlower_talloc(state, npipe);
87         if (tevent_req_nomem(lower_case_npipe, req)) {
88                 goto post;
89         }
90
91         state->unix_path = talloc_asprintf(state, "%s/%s",
92                                            directory,
93                                            lower_case_npipe);
94         talloc_free(lower_case_npipe);
95         if (tevent_req_nomem(state->unix_path, req)) {
96                 goto post;
97         }
98
99         ret = tsocket_address_unix_from_path(state,
100                                              "",
101                                              &state->unix_laddr);
102         if (ret == -1) {
103                 tevent_req_error(req, errno);
104                 goto post;
105         }
106
107         ret = tsocket_address_unix_from_path(state,
108                                              state->unix_path,
109                                              &state->unix_raddr);
110         if (ret == -1) {
111                 tevent_req_error(req, errno);
112                 goto post;
113         }
114
115         ZERO_STRUCT(state->auth_req);
116         if (client) {
117                 struct named_pipe_auth_req_info3 *info3;
118
119                 if (!server) {
120                         tevent_req_error(req, EINVAL);
121                         goto post;
122                 }
123
124                 state->auth_req.level = 3;
125                 info3 = &state->auth_req.info.info3;
126
127                 info3->client_name = client_name_in;
128                 info3->client_addr = tsocket_address_inet_addr_string(client, state);
129                 if (!info3->client_addr) {
130                         /* errno might be EINVAL */
131                         tevent_req_error(req, errno);
132                         goto post;
133                 }
134                 info3->client_port = tsocket_address_inet_port(client);
135                 if (!info3->client_name) {
136                         info3->client_name = info3->client_addr;
137                 }
138
139                 info3->server_addr = tsocket_address_inet_addr_string(server, state);
140                 if (!info3->server_addr) {
141                         /* errno might be EINVAL */
142                         tevent_req_error(req, errno);
143                         goto post;
144                 }
145                 info3->server_port = tsocket_address_inet_port(server);
146                 if (!info3->server_name) {
147                         info3->server_name = info3->server_addr;
148                 }
149
150                 info3->sam_info3 = discard_const_p(struct netr_SamInfo3, sam_info3);
151                 info3->session_key_length = session_key.length;
152                 info3->session_key = session_key.data;
153                 info3->gssapi_delegated_creds_length = delegated_creds.length;
154                 info3->gssapi_delegated_creds = delegated_creds.data;
155
156         } else if (sam_info3) {
157                 state->auth_req.level = 1;
158                 state->auth_req.info.info1 = *sam_info3;
159         } else {
160                 state->auth_req.level = 0;
161         }
162
163         if (DEBUGLVL(10)) {
164                 NDR_PRINT_DEBUG(named_pipe_auth_req, &state->auth_req);
165         }
166
167         ndr_err = ndr_push_struct_blob(&state->auth_req_blob,
168                         state, &state->auth_req,
169                         (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
170         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
171                 tevent_req_error(req, EINVAL);
172                 goto post;
173         }
174
175         state->auth_req_iov.iov_base = state->auth_req_blob.data;
176         state->auth_req_iov.iov_len = state->auth_req_blob.length;
177
178         subreq = tstream_unix_connect_send(state,
179                                            state->caller.ev,
180                                            state->unix_laddr,
181                                            state->unix_raddr);
182         if (tevent_req_nomem(subreq, req)) {
183                 goto post;
184         }
185         tevent_req_set_callback(subreq, tstream_npa_connect_unix_done, req);
186
187         return req;
188
189 post:
190         tevent_req_post(req, ev);
191         return req;
192 }
193
194 static void tstream_npa_connect_writev_done(struct tevent_req *subreq);
195
196 static void tstream_npa_connect_unix_done(struct tevent_req *subreq)
197 {
198         struct tevent_req *req =
199                 tevent_req_callback_data(subreq,
200                 struct tevent_req);
201         struct tstream_npa_connect_state *state =
202                 tevent_req_data(req,
203                 struct tstream_npa_connect_state);
204         int ret;
205         int sys_errno;
206
207         ret = tstream_unix_connect_recv(subreq, &sys_errno,
208                                         state, &state->unix_stream);
209         TALLOC_FREE(subreq);
210         if (ret == -1) {
211                 tevent_req_error(req, sys_errno);
212                 return;
213         }
214
215         subreq = tstream_writev_send(state,
216                                      state->caller.ev,
217                                      state->unix_stream,
218                                      &state->auth_req_iov, 1);
219         if (tevent_req_nomem(subreq, req)) {
220                 return;
221         }
222         tevent_req_set_callback(subreq, tstream_npa_connect_writev_done, req);
223 }
224
225 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
226                                            void *private_data,
227                                            TALLOC_CTX *mem_ctx,
228                                            struct iovec **_vector,
229                                            size_t *_count);
230 static void tstream_npa_connect_readv_done(struct tevent_req *subreq);
231
232 static void tstream_npa_connect_writev_done(struct tevent_req *subreq)
233 {
234         struct tevent_req *req =
235                 tevent_req_callback_data(subreq,
236                 struct tevent_req);
237         struct tstream_npa_connect_state *state =
238                 tevent_req_data(req,
239                 struct tstream_npa_connect_state);
240         int ret;
241         int sys_errno;
242
243         ret = tstream_writev_recv(subreq, &sys_errno);
244         TALLOC_FREE(subreq);
245         if (ret == -1) {
246                 tevent_req_error(req, sys_errno);
247                 return;
248         }
249
250         state->auth_rep_blob = data_blob_const(NULL, 0);
251
252         subreq = tstream_readv_pdu_send(state, state->caller.ev,
253                                         state->unix_stream,
254                                         tstream_npa_connect_next_vector,
255                                         state);
256         if (tevent_req_nomem(subreq, req)) {
257                 return;
258         }
259         tevent_req_set_callback(subreq, tstream_npa_connect_readv_done, req);
260 }
261
262 static int tstream_npa_connect_next_vector(struct tstream_context *unix_stream,
263                                            void *private_data,
264                                            TALLOC_CTX *mem_ctx,
265                                            struct iovec **_vector,
266                                            size_t *_count)
267 {
268         struct tstream_npa_connect_state *state = talloc_get_type_abort(private_data,
269                                         struct tstream_npa_connect_state);
270         struct iovec *vector;
271         size_t count;
272         off_t ofs = 0;
273
274         if (state->auth_rep_blob.length == 0) {
275                 state->auth_rep_blob = data_blob_talloc(state, NULL, 4);
276                 if (!state->auth_rep_blob.data) {
277                         return -1;
278                 }
279         } else if (state->auth_rep_blob.length == 4) {
280                 uint32_t msg_len;
281
282                 ofs = 4;
283
284                 msg_len = RIVAL(state->auth_rep_blob.data, 0);
285
286                 if (msg_len > 0x00FFFFFF) {
287                         errno = EMSGSIZE;
288                         return -1;
289                 }
290
291                 if (msg_len == 0) {
292                         errno = EMSGSIZE;
293                         return -1;
294                 }
295
296                 msg_len += ofs;
297
298                 state->auth_rep_blob.data = talloc_realloc(state,
299                                                 state->auth_rep_blob.data,
300                                                 uint8_t, msg_len);
301                 if (!state->auth_rep_blob.data) {
302                         return -1;
303                 }
304                 state->auth_rep_blob.length = msg_len;
305         } else {
306                 *_vector = NULL;
307                 *_count = 0;
308                 return 0;
309         }
310
311         /* we need to get a message header */
312         vector = talloc_array(mem_ctx, struct iovec, 1);
313         if (!vector) {
314                 return -1;
315         }
316         vector[0].iov_base = state->auth_rep_blob.data + ofs;
317         vector[0].iov_len = state->auth_rep_blob.length - ofs;
318         count = 1;
319
320         *_vector = vector;
321         *_count = count;
322         return 0;
323 }
324
325 static void tstream_npa_connect_readv_done(struct tevent_req *subreq)
326 {
327         struct tevent_req *req =
328                 tevent_req_callback_data(subreq,
329                 struct tevent_req);
330         struct tstream_npa_connect_state *state =
331                 tevent_req_data(req,
332                 struct tstream_npa_connect_state);
333         int ret;
334         int sys_errno;
335         enum ndr_err_code ndr_err;
336
337         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
338         TALLOC_FREE(subreq);
339         if (ret == -1) {
340                 tevent_req_error(req, sys_errno);
341                 return;
342         }
343
344         DEBUG(10,("name_pipe_auth_rep(client)[%u]\n",
345                  (uint32_t)state->auth_rep_blob.length));
346         dump_data(11, state->auth_rep_blob.data, state->auth_rep_blob.length);
347
348         ndr_err = ndr_pull_struct_blob(
349                 &state->auth_rep_blob, state,
350                 &state->auth_rep,
351                 (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
352
353         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
354                 DEBUG(0, ("ndr_pull_named_pipe_auth_rep failed: %s\n",
355                           ndr_map_error2string(ndr_err)));
356                 tevent_req_error(req, EIO);
357                 return;
358         }
359
360         if (DEBUGLVL(10)) {
361                 NDR_PRINT_DEBUG(named_pipe_auth_rep, &state->auth_rep);
362         }
363
364         if (state->auth_rep.length < 16) {
365                 DEBUG(0, ("req invalid length: %u < 16\n",
366                           state->auth_rep.length));
367                 tevent_req_error(req, EIO);
368                 return;
369         }
370
371         if (strcmp(NAMED_PIPE_AUTH_MAGIC, state->auth_rep.magic) != 0) {
372                 DEBUG(0, ("req invalid magic: %s != %s\n",
373                           state->auth_rep.magic, NAMED_PIPE_AUTH_MAGIC));
374                 tevent_req_error(req, EIO);
375                 return;
376         }
377
378         if (!NT_STATUS_IS_OK(state->auth_rep.status)) {
379                 DEBUG(0, ("req failed: %s\n",
380                           nt_errstr(state->auth_rep.status)));
381                 tevent_req_error(req, EACCES);
382                 return;
383         }
384
385         if (state->auth_rep.level != state->auth_req.level) {
386                 DEBUG(0, ("req invalid level: %u != %u\n",
387                           state->auth_rep.level, state->auth_req.level));
388                 tevent_req_error(req, EIO);
389                 return;
390         }
391
392         tevent_req_done(req);
393 }
394
395 int _tstream_npa_connect_recv(struct tevent_req *req,
396                               int *perrno,
397                               TALLOC_CTX *mem_ctx,
398                               struct tstream_context **_stream,
399                               uint16_t *_file_type,
400                               uint16_t *_device_state,
401                               uint64_t *_allocation_size,
402                               const char *location)
403 {
404         struct tstream_npa_connect_state *state =
405                 tevent_req_data(req,
406                 struct tstream_npa_connect_state);
407         struct tstream_context *stream;
408         struct tstream_npa *npas;
409         uint16_t device_state = 0;
410         uint64_t allocation_size = 0;
411
412         if (tevent_req_is_unix_error(req, perrno)) {
413                 tevent_req_received(req);
414                 return -1;
415         }
416
417         stream = tstream_context_create(mem_ctx,
418                                         &tstream_npa_ops,
419                                         &npas,
420                                         struct tstream_npa,
421                                         location);
422         if (!stream) {
423                 *perrno = ENOMEM;
424                 tevent_req_received(req);
425                 return -1;
426         }
427         ZERO_STRUCTP(npas);
428
429         npas->unix_stream = talloc_move(stream, &state->unix_stream);
430         switch (state->auth_rep.level) {
431         case 0:
432         case 1:
433                 npas->file_type = FILE_TYPE_BYTE_MODE_PIPE;
434                 device_state = 0x00ff;
435                 allocation_size = 2048;
436                 break;
437         case 2:
438                 npas->file_type = state->auth_rep.info.info2.file_type;
439                 device_state = state->auth_rep.info.info2.device_state;
440                 allocation_size = state->auth_rep.info.info2.allocation_size;
441                 break;
442         case 3:
443                 npas->file_type = state->auth_rep.info.info3.file_type;
444                 device_state = state->auth_rep.info.info3.device_state;
445                 allocation_size = state->auth_rep.info.info3.allocation_size;
446                 break;
447         }
448
449         *_stream = stream;
450         *_file_type = npas->file_type;
451         *_device_state = device_state;
452         *_allocation_size = allocation_size;
453         tevent_req_received(req);
454         return 0;
455 }
456
457 static ssize_t tstream_npa_pending_bytes(struct tstream_context *stream)
458 {
459         struct tstream_npa *npas = tstream_context_data(stream,
460                                    struct tstream_npa);
461         ssize_t ret;
462
463         if (!npas->unix_stream) {
464                 errno = ENOTCONN;
465                 return -1;
466         }
467
468         switch (npas->file_type) {
469         case FILE_TYPE_BYTE_MODE_PIPE:
470                 ret = tstream_pending_bytes(npas->unix_stream);
471                 break;
472
473         case FILE_TYPE_MESSAGE_MODE_PIPE:
474                 ret = npas->pending.iov_len;
475                 break;
476
477         default:
478                 ret = -1;
479         }
480
481         return ret;
482 }
483
484 struct tstream_npa_readv_state {
485         struct tstream_context *stream;
486
487         struct iovec *vector;
488         size_t count;
489
490         /* the header for message mode */
491         uint8_t hdr[2];
492         bool wait_for_hdr;
493
494         int ret;
495 };
496
497 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq);
498 static int tstream_npa_readv_next_vector(struct tstream_context *stream,
499                                          void *private_data,
500                                          TALLOC_CTX *mem_ctx,
501                                          struct iovec **_vector,
502                                          size_t *_count);
503 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq);
504
505 static struct tevent_req *tstream_npa_readv_send(TALLOC_CTX *mem_ctx,
506                                         struct tevent_context *ev,
507                                         struct tstream_context *stream,
508                                         struct iovec *vector,
509                                         size_t count)
510 {
511         struct tevent_req *req;
512         struct tstream_npa_readv_state *state;
513         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
514         struct tevent_req *subreq;
515         off_t ofs;
516         size_t left;
517         uint8_t *pbase;
518
519         req = tevent_req_create(mem_ctx, &state,
520                                 struct tstream_npa_readv_state);
521         if (!req) {
522                 return NULL;
523         }
524
525         state->stream   = stream;
526         state->ret      = 0;
527
528         if (!npas->unix_stream) {
529                 tevent_req_error(req, ENOTCONN);
530                 goto post;
531         }
532
533         switch (npas->file_type) {
534         case FILE_TYPE_BYTE_MODE_PIPE:
535                 state->vector = vector;
536                 state->count = count;
537
538                 subreq = tstream_readv_send(state,
539                                             ev,
540                                             npas->unix_stream,
541                                             state->vector,
542                                             state->count);
543                 if (tevent_req_nomem(subreq,req)) {
544                         goto post;
545                 }
546                 tevent_req_set_callback(subreq,
547                                         tstream_npa_readv_byte_mode_handler,
548                                         req);
549
550                 return req;
551
552         case FILE_TYPE_MESSAGE_MODE_PIPE:
553                 /*
554                  * we make a copy of the vector and prepend a header
555                  * with the length
556                  */
557                 state->vector   = talloc_array(state, struct iovec, count);
558                 if (tevent_req_nomem(state->vector, req)) {
559                         goto post;
560                 }
561                 memcpy(state->vector, vector, sizeof(struct iovec)*count);
562                 state->count = count;
563
564                 /*
565                  * copy the pending buffer first
566                  */
567                 ofs = 0;
568                 left = npas->pending.iov_len;
569                 pbase = (uint8_t *)npas->pending.iov_base;
570
571                 while (left > 0 && state->count > 0) {
572                         uint8_t *base;
573                         base = (uint8_t *)state->vector[0].iov_base;
574                         if (left < state->vector[0].iov_len) {
575                                 memcpy(base, pbase + ofs, left);
576
577                                 base += left;
578                                 state->vector[0].iov_base = base;
579                                 state->vector[0].iov_len -= left;
580
581                                 ofs += left;
582                                 left = 0;
583                                 TALLOC_FREE(pbase);
584                                 ZERO_STRUCT(npas->pending);
585                                 break;
586                         }
587                         memcpy(base, pbase + ofs, state->vector[0].iov_len);
588
589                         ofs += state->vector[0].iov_len;
590                         left -= state->vector[0].iov_len;
591                         state->vector += 1;
592                         state->count -= 1;
593
594                         if (left == 0) {
595                                 TALLOC_FREE(pbase);
596                                 ZERO_STRUCT(npas->pending);
597                                 break;
598                         }
599                 }
600
601                 if (left > 0) {
602                         memmove(pbase, pbase + ofs, left);
603                         npas->pending.iov_base = pbase;
604                         npas->pending.iov_len = left;
605                         /*
606                          * this cannot fail and even if it
607                          * fails we can handle it
608                          */
609                         pbase = talloc_realloc(npas, pbase, uint8_t, left);
610                         if (pbase) {
611                                 npas->pending.iov_base = pbase;
612                         }
613                         pbase = NULL;
614                 }
615
616                 state->ret += ofs;
617
618                 if (state->count == 0) {
619                         tevent_req_done(req);
620                         goto post;
621                 }
622
623                 ZERO_STRUCT(state->hdr);
624                 state->wait_for_hdr = false;
625
626                 subreq = tstream_readv_pdu_send(state,
627                                                 ev,
628                                                 npas->unix_stream,
629                                                 tstream_npa_readv_next_vector,
630                                                 state);
631                 if (tevent_req_nomem(subreq, req)) {
632                         goto post;
633                 }
634                 tevent_req_set_callback(subreq,
635                                         tstream_npa_readv_msg_mode_handler,
636                                         req);
637
638                 return req;
639         }
640
641         /* this can't happen */
642         tevent_req_error(req, EINVAL);
643         goto post;
644
645  post:
646         tevent_req_post(req, ev);
647         return req;
648 }
649
650 static void tstream_npa_readv_byte_mode_handler(struct tevent_req *subreq)
651 {
652         struct tevent_req *req = tevent_req_callback_data(subreq,
653                                  struct tevent_req);
654         struct tstream_npa_readv_state *state = tevent_req_data(req,
655                                         struct tstream_npa_readv_state);
656         int ret;
657         int sys_errno;
658
659         ret = tstream_readv_recv(subreq, &sys_errno);
660         TALLOC_FREE(subreq);
661         if (ret == -1) {
662                 tevent_req_error(req, sys_errno);
663                 return;
664         }
665
666         state->ret = ret;
667
668         tevent_req_done(req);
669 }
670
671 static int tstream_npa_readv_next_vector(struct tstream_context *unix_stream,
672                                          void *private_data,
673                                          TALLOC_CTX *mem_ctx,
674                                          struct iovec **_vector,
675                                          size_t *_count)
676 {
677         struct tstream_npa_readv_state *state = talloc_get_type_abort(private_data,
678                                         struct tstream_npa_readv_state);
679         struct tstream_npa *npas = tstream_context_data(state->stream,
680                                    struct tstream_npa);
681         struct iovec *vector;
682         size_t count;
683         uint16_t msg_len;
684         size_t left;
685
686         if (state->count == 0) {
687                 *_vector = NULL;
688                 *_count = 0;
689                 return 0;
690         }
691
692         if (!state->wait_for_hdr) {
693                 /* we need to get a message header */
694                 vector = talloc_array(mem_ctx, struct iovec, 1);
695                 if (!vector) {
696                         return -1;
697                 }
698                 ZERO_STRUCT(state->hdr);
699                 vector[0].iov_base = state->hdr;
700                 vector[0].iov_len = sizeof(state->hdr);
701
702                 count = 1;
703
704                 state->wait_for_hdr = true;
705
706                 *_vector = vector;
707                 *_count = count;
708                 return 0;
709         }
710
711         /* and now fill the callers buffers and maybe the pending buffer */
712         state->wait_for_hdr = false;
713
714         msg_len = SVAL(state->hdr, 0);
715
716         if (msg_len == 0) {
717                 errno = EIO;
718                 return -1;
719         }
720
721         state->wait_for_hdr = false;
722
723         /* +1 because we may need to fill the pending buffer */
724         vector = talloc_array(mem_ctx, struct iovec, state->count + 1);
725         if (!vector) {
726                 return -1;
727         }
728
729         count = 0;
730         left = msg_len;
731         while (left > 0 && state->count > 0) {
732                 if (left < state->vector[0].iov_len) {
733                         uint8_t *base;
734                         base = (uint8_t *)state->vector[0].iov_base;
735                         vector[count].iov_base = base;
736                         vector[count].iov_len = left;
737                         count++;
738                         base += left;
739                         state->vector[0].iov_base = base;
740                         state->vector[0].iov_len -= left;
741                         break;
742                 }
743                 vector[count] = state->vector[0];
744                 count++;
745                 left -= state->vector[0].iov_len;
746                 state->vector += 1;
747                 state->count -= 1;
748         }
749
750         if (left > 0) {
751                 /*
752                  * if the message is longer than the buffers the caller
753                  * requested, we need to consume the rest of the message
754                  * into the pending buffer, where the next readv can
755                  * be served from.
756                  */
757                 npas->pending.iov_base = talloc_array(npas, uint8_t, left);
758                 if (!npas->pending.iov_base) {
759                         return -1;
760                 }
761                 npas->pending.iov_len = left;
762
763                 vector[count] = npas->pending;
764                 count++;
765         }
766
767         state->ret += (msg_len - left);
768
769         *_vector = vector;
770         *_count = count;
771         return 0;
772 }
773
774 static void tstream_npa_readv_msg_mode_handler(struct tevent_req *subreq)
775 {
776         struct tevent_req *req = tevent_req_callback_data(subreq,
777                                  struct tevent_req);
778         int ret;
779         int sys_errno;
780
781         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
782         TALLOC_FREE(subreq);
783         if (ret == -1) {
784                 tevent_req_error(req, sys_errno);
785                 return;
786         }
787
788         /*
789          * we do not set state->ret here as ret includes the headr size.
790          * we set it in tstream_npa_readv_pdu_next_vector()
791          */
792
793         tevent_req_done(req);
794 }
795
796 static int tstream_npa_readv_recv(struct tevent_req *req,
797                                    int *perrno)
798 {
799         struct tstream_npa_readv_state *state = tevent_req_data(req,
800                                         struct tstream_npa_readv_state);
801         int ret;
802
803         ret = tsocket_simple_int_recv(req, perrno);
804         if (ret == 0) {
805                 ret = state->ret;
806         }
807
808         tevent_req_received(req);
809         return ret;
810 }
811
812 struct tstream_npa_writev_state {
813         const struct iovec *vector;
814         size_t count;
815
816         /* the header for message mode */
817         bool hdr_used;
818         uint8_t hdr[2];
819
820         int ret;
821 };
822
823 static void tstream_npa_writev_handler(struct tevent_req *subreq);
824
825 static struct tevent_req *tstream_npa_writev_send(TALLOC_CTX *mem_ctx,
826                                         struct tevent_context *ev,
827                                         struct tstream_context *stream,
828                                         const struct iovec *vector,
829                                         size_t count)
830 {
831         struct tevent_req *req;
832         struct tstream_npa_writev_state *state;
833         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
834         struct tevent_req *subreq;
835         size_t msg_len;
836         size_t i;
837         struct iovec *new_vector;
838
839         req = tevent_req_create(mem_ctx, &state,
840                                 struct tstream_npa_writev_state);
841         if (!req) {
842                 return NULL;
843         }
844
845         state->ret      = 0;
846
847         if (!npas->unix_stream) {
848                 tevent_req_error(req, ENOTCONN);
849                 goto post;
850         }
851
852         switch (npas->file_type) {
853         case FILE_TYPE_BYTE_MODE_PIPE:
854                 state->hdr_used = false;
855                 state->vector   = vector;
856                 state->count    = count;
857                 break;
858
859         case FILE_TYPE_MESSAGE_MODE_PIPE:
860                 /*
861                  * we make a copy of the vector and prepend a header
862                  * with the length
863                  */
864                 new_vector      = talloc_array(state, struct iovec, count + 1);
865                 if (tevent_req_nomem(new_vector, req)) {
866                         goto post;
867                 }
868                 new_vector[0].iov_base = state->hdr;
869                 new_vector[0].iov_len = sizeof(state->hdr);
870                 memcpy(new_vector + 1, vector, sizeof(struct iovec)*count);
871
872                 state->hdr_used = true;
873                 state->vector   = new_vector;
874                 state->count    = count + 1;
875
876                 msg_len = 0;
877                 for (i=0; i < count; i++) {
878                         msg_len += vector[i].iov_len;
879                 }
880
881                 if (msg_len > UINT16_MAX) {
882                         tevent_req_error(req, EMSGSIZE);
883                         goto post;
884                 }
885
886                 SSVAL(state->hdr, 0, msg_len);
887                 break;
888         }
889
890         subreq = tstream_writev_send(state,
891                                      ev,
892                                      npas->unix_stream,
893                                      state->vector,
894                                      state->count);
895         if (tevent_req_nomem(subreq, req)) {
896                 goto post;
897         }
898         tevent_req_set_callback(subreq, tstream_npa_writev_handler, req);
899
900         return req;
901
902  post:
903         tevent_req_post(req, ev);
904         return req;
905 }
906
907 static void tstream_npa_writev_handler(struct tevent_req *subreq)
908 {
909         struct tevent_req *req = tevent_req_callback_data(subreq,
910                                  struct tevent_req);
911         struct tstream_npa_writev_state *state = tevent_req_data(req,
912                                         struct tstream_npa_writev_state);
913         int ret;
914         int sys_errno;
915
916         ret = tstream_writev_recv(subreq, &sys_errno);
917         TALLOC_FREE(subreq);
918         if (ret == -1) {
919                 tevent_req_error(req, sys_errno);
920                 return;
921         }
922
923         /*
924          * in message mode we need to hide the length
925          * of the hdr from the caller
926          */
927         if (state->hdr_used) {
928                 ret -= sizeof(state->hdr);
929         }
930
931         state->ret = ret;
932
933         tevent_req_done(req);
934 }
935
936 static int tstream_npa_writev_recv(struct tevent_req *req,
937                                    int *perrno)
938 {
939         struct tstream_npa_writev_state *state = tevent_req_data(req,
940                                         struct tstream_npa_writev_state);
941         int ret;
942
943         ret = tsocket_simple_int_recv(req, perrno);
944         if (ret == 0) {
945                 ret = state->ret;
946         }
947
948         tevent_req_received(req);
949         return ret;
950 }
951
952 struct tstream_npa_disconnect_state {
953         struct tstream_context *stream;
954 };
955
956 static void tstream_npa_disconnect_handler(struct tevent_req *subreq);
957
958 static struct tevent_req *tstream_npa_disconnect_send(TALLOC_CTX *mem_ctx,
959                                                 struct tevent_context *ev,
960                                                 struct tstream_context *stream)
961 {
962         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
963         struct tevent_req *req;
964         struct tstream_npa_disconnect_state *state;
965         struct tevent_req *subreq;
966
967         req = tevent_req_create(mem_ctx, &state,
968                                 struct tstream_npa_disconnect_state);
969         if (req == NULL) {
970                 return NULL;
971         }
972
973         state->stream = stream;
974
975         if (!npas->unix_stream) {
976                 tevent_req_error(req, ENOTCONN);
977                 goto post;
978         }
979
980         subreq = tstream_disconnect_send(state,
981                                          ev,
982                                          npas->unix_stream);
983         if (tevent_req_nomem(subreq, req)) {
984                 goto post;
985         }
986         tevent_req_set_callback(subreq, tstream_npa_disconnect_handler, req);
987
988         return req;
989
990 post:
991         tevent_req_post(req, ev);
992         return req;
993 }
994
995 static void tstream_npa_disconnect_handler(struct tevent_req *subreq)
996 {
997         struct tevent_req *req = tevent_req_callback_data(subreq,
998                                  struct tevent_req);
999         struct tstream_npa_disconnect_state *state = tevent_req_data(req,
1000                                         struct tstream_npa_disconnect_state);
1001         struct tstream_context *stream = state->stream;
1002         struct tstream_npa *npas = tstream_context_data(stream, struct tstream_npa);
1003         int ret;
1004         int sys_errno;
1005
1006         ret = tstream_disconnect_recv(subreq, &sys_errno);
1007         TALLOC_FREE(subreq);
1008         if (ret == -1) {
1009                 tevent_req_error(req, sys_errno);
1010                 return;
1011         }
1012
1013         TALLOC_FREE(npas->unix_stream);
1014
1015         tevent_req_done(req);
1016 }
1017
1018 static int tstream_npa_disconnect_recv(struct tevent_req *req,
1019                                        int *perrno)
1020 {
1021         int ret;
1022
1023         ret = tsocket_simple_int_recv(req, perrno);
1024
1025         tevent_req_received(req);
1026         return ret;
1027 }
1028
1029 static const struct tstream_context_ops tstream_npa_ops = {
1030         .name                   = "npa",
1031
1032         .pending_bytes          = tstream_npa_pending_bytes,
1033
1034         .readv_send             = tstream_npa_readv_send,
1035         .readv_recv             = tstream_npa_readv_recv,
1036
1037         .writev_send            = tstream_npa_writev_send,
1038         .writev_recv            = tstream_npa_writev_recv,
1039
1040         .disconnect_send        = tstream_npa_disconnect_send,
1041         .disconnect_recv        = tstream_npa_disconnect_recv,
1042 };
1043
1044 int _tstream_npa_existing_socket(TALLOC_CTX *mem_ctx,
1045                                  int fd,
1046                                  uint16_t file_type,
1047                                  struct tstream_context **_stream,
1048                                  const char *location)
1049 {
1050         struct tstream_context *stream;
1051         struct tstream_npa *npas;
1052         int ret;
1053
1054         switch (file_type) {
1055         case FILE_TYPE_BYTE_MODE_PIPE:
1056                 break;
1057         case FILE_TYPE_MESSAGE_MODE_PIPE:
1058                 break;
1059         default:
1060                 errno = EINVAL;
1061                 return -1;
1062         }
1063
1064         stream = tstream_context_create(mem_ctx,
1065                                         &tstream_npa_ops,
1066                                         &npas,
1067                                         struct tstream_npa,
1068                                         location);
1069         if (!stream) {
1070                 return -1;
1071         }
1072         ZERO_STRUCTP(npas);
1073
1074         npas->file_type = file_type;
1075
1076         ret = tstream_bsd_existing_socket(stream, fd,
1077                                           &npas->unix_stream);
1078         if (ret == -1) {
1079                 int saved_errno = errno;
1080                 talloc_free(stream);
1081                 errno = saved_errno;
1082                 return -1;
1083         }
1084
1085         *_stream = stream;
1086         return 0;
1087 }
1088
1089
1090 struct tstream_npa_accept_state {
1091         struct tevent_context *ev;
1092         struct tstream_context *plain;
1093         uint16_t file_type;
1094         uint16_t device_state;
1095         uint64_t alloc_size;
1096
1097         DATA_BLOB npa_blob;
1098         struct iovec out_iov;
1099
1100         /* results */
1101         NTSTATUS accept_status;
1102         struct tsocket_address *client;
1103         char *client_name;
1104         struct tsocket_address *server;
1105         char *server_name;
1106         struct netr_SamInfo3 *info3;
1107         DATA_BLOB session_key;
1108         DATA_BLOB delegated_creds;
1109 };
1110
1111 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1112                                           void *private_data,
1113                                           TALLOC_CTX *mem_ctx,
1114                                           struct iovec **_vector,
1115                                           size_t *_count);
1116 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq);
1117 static void tstream_npa_accept_existing_done(struct tevent_req *subreq);
1118
1119 struct tevent_req *tstream_npa_accept_existing_send(TALLOC_CTX *mem_ctx,
1120                                         struct tevent_context *ev,
1121                                         struct tstream_context *plain,
1122                                         uint16_t file_type,
1123                                         uint16_t device_state,
1124                                         uint64_t allocation_size)
1125 {
1126         struct tstream_npa_accept_state *state;
1127         struct tevent_req *req, *subreq;
1128
1129         req = tevent_req_create(mem_ctx, &state,
1130                                 struct tstream_npa_accept_state);
1131         if (req == NULL) {
1132                 return NULL;
1133         }
1134
1135         switch (file_type) {
1136         case FILE_TYPE_BYTE_MODE_PIPE:
1137                 break;
1138         case FILE_TYPE_MESSAGE_MODE_PIPE:
1139                 break;
1140         default:
1141                 tevent_req_error(req, EINVAL);
1142                 goto post;
1143         }
1144
1145         ZERO_STRUCTP(state);
1146
1147         state->ev = ev;
1148         state->plain = plain;
1149         state->file_type = file_type;
1150         state->device_state = device_state;
1151         state->alloc_size = allocation_size;
1152
1153         /*
1154          * The named pipe pdu's have the length as 8 byte (initial_read_size),
1155          * named_pipe_full_request provides the pdu length then.
1156          */
1157         subreq = tstream_readv_pdu_send(state, ev, plain,
1158                                         tstream_npa_accept_next_vector,
1159                                         state);
1160         if (tevent_req_nomem(subreq, req)) {
1161                 goto post;
1162         }
1163
1164         tevent_req_set_callback(subreq,
1165                                 tstream_npa_accept_existing_reply, req);
1166
1167         return req;
1168
1169 post:
1170         tevent_req_post(req, ev);
1171         return req;
1172 }
1173
1174 static int tstream_npa_accept_next_vector(struct tstream_context *unix_stream,
1175                                           void *private_data,
1176                                           TALLOC_CTX *mem_ctx,
1177                                           struct iovec **_vector,
1178                                           size_t *_count)
1179 {
1180         struct tstream_npa_accept_state *state =
1181                 talloc_get_type_abort(private_data,
1182                                         struct tstream_npa_accept_state);
1183         struct iovec *vector;
1184         size_t count;
1185         off_t ofs = 0;
1186
1187         if (state->npa_blob.length == 0) {
1188                 state->npa_blob = data_blob_talloc(state, NULL, 4);
1189                 if (!state->npa_blob.data) {
1190                         return -1;
1191                 }
1192         } else if (state->npa_blob.length == 4) {
1193                 uint32_t msg_len;
1194
1195                 ofs = 4;
1196
1197                 msg_len = RIVAL(state->npa_blob.data, 0);
1198
1199                 if (msg_len > 0x00FFFFFF) {
1200                         errno = EMSGSIZE;
1201                         return -1;
1202                 }
1203
1204                 if (msg_len == 0) {
1205                         errno = EMSGSIZE;
1206                         return -1;
1207                 }
1208
1209                 msg_len += ofs;
1210
1211                 state->npa_blob.data = talloc_realloc(state,
1212                                                       state->npa_blob.data,
1213                                                       uint8_t, msg_len);
1214                 if (!state->npa_blob.data) {
1215                         return -1;
1216                 }
1217                 state->npa_blob.length = msg_len;
1218         } else {
1219                 if (memcmp(&state->npa_blob.data[4],
1220                            NAMED_PIPE_AUTH_MAGIC, 4) != 0) {
1221                         DEBUG(0, ("Wrong protocol\n"));
1222 #if defined(EPROTONOSUPPORT)
1223                         errno = EPROTONOSUPPORT;
1224 #elif defined(EPROTO)
1225                         errno = EPROTO;
1226 #else
1227                         errno = EINVAL;
1228 #endif
1229                         return -1;
1230                 }
1231                 *_vector = NULL;
1232                 *_count = 0;
1233                 return 0;
1234         }
1235
1236         /* we need to get a message header */
1237         vector = talloc_array(mem_ctx, struct iovec, 1);
1238         if (!vector) {
1239                 return -1;
1240         }
1241         vector[0].iov_base = state->npa_blob.data + ofs;
1242         vector[0].iov_len = state->npa_blob.length - ofs;
1243         count = 1;
1244
1245         *_vector = vector;
1246         *_count = count;
1247         return 0;
1248 }
1249
1250 static void tstream_npa_accept_existing_reply(struct tevent_req *subreq)
1251 {
1252         struct tevent_req *req =
1253                         tevent_req_callback_data(subreq, struct tevent_req);
1254         struct tstream_npa_accept_state *state =
1255                         tevent_req_data(req, struct tstream_npa_accept_state);
1256         struct named_pipe_auth_req *pipe_request;
1257         struct named_pipe_auth_rep pipe_reply;
1258         struct named_pipe_auth_req_info3 i3;
1259         enum ndr_err_code ndr_err;
1260         DATA_BLOB out;
1261         int sys_errno;
1262         int ret;
1263
1264         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
1265         TALLOC_FREE(subreq);
1266         if (ret == -1) {
1267                 tevent_req_error(req, sys_errno);
1268                 return;
1269         }
1270
1271         DEBUG(10, ("Received packet of length %lu\n",
1272                    (long)state->npa_blob.length));
1273         dump_data(11, state->npa_blob.data, state->npa_blob.length);
1274
1275         ZERO_STRUCT(pipe_reply);
1276         pipe_reply.level = 0;
1277         pipe_reply.status = NT_STATUS_INTERNAL_ERROR;
1278         /*
1279          * TODO: check it's a root (uid == 0) pipe
1280          */
1281
1282         pipe_request = talloc(state, struct named_pipe_auth_req);
1283         if (!pipe_request) {
1284                 DEBUG(0, ("Out of memory!\n"));
1285                 goto reply;
1286         }
1287
1288         /* parse the passed credentials */
1289         ndr_err = ndr_pull_struct_blob_all(
1290                         &state->npa_blob, pipe_request, pipe_request,
1291                         (ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_req);
1292         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293                 pipe_reply.status = ndr_map_error2ntstatus(ndr_err);
1294                 DEBUG(2, ("Could not unmarshall named_pipe_auth_req: %s\n",
1295                           nt_errstr(pipe_reply.status)));
1296                 goto reply;
1297         }
1298
1299         if (DEBUGLVL(10)) {
1300                 NDR_PRINT_DEBUG(named_pipe_auth_req, pipe_request);
1301         }
1302
1303         ZERO_STRUCT(i3);
1304
1305         switch (pipe_request->level) {
1306         case 0:
1307                 pipe_reply.level = 0;
1308                 pipe_reply.status = NT_STATUS_OK;
1309
1310                 /* we need to force byte mode in this level */
1311                 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1312                 break;
1313
1314         case 1:
1315                 pipe_reply.level = 1;
1316                 pipe_reply.status = NT_STATUS_OK;
1317
1318                 /* We must copy net3_SamInfo3, so that
1319                  * info3 is an actual talloc pointer, then we steal
1320                  * pipe_request on info3 so that all the allocated memory
1321                  * pointed by the structrue members is preserved */
1322                 state->info3 = (struct netr_SamInfo3 *)talloc_memdup(state,
1323                                                 &pipe_request->info.info1,
1324                                                 sizeof(struct netr_SamInfo3));
1325                 if (!state->info3) {
1326                         pipe_reply.status = NT_STATUS_NO_MEMORY;
1327                         DEBUG(0, ("Out of memory!\n"));
1328                         goto reply;
1329                 }
1330                 talloc_steal(state->info3, pipe_request);
1331
1332                 /* we need to force byte mode in this level */
1333                 state->file_type = FILE_TYPE_BYTE_MODE_PIPE;
1334                 break;
1335
1336         case 2:
1337                 pipe_reply.level = 2;
1338                 pipe_reply.status = NT_STATUS_OK;
1339                 pipe_reply.info.info2.file_type = state->file_type;
1340                 pipe_reply.info.info2.device_state = state->device_state;
1341                 pipe_reply.info.info2.allocation_size = state->alloc_size;
1342
1343                 i3.client_name = pipe_request->info.info2.client_name;
1344                 i3.client_addr = pipe_request->info.info2.client_addr;
1345                 i3.client_port = pipe_request->info.info2.client_port;
1346                 i3.server_name = pipe_request->info.info2.server_name;
1347                 i3.server_addr = pipe_request->info.info2.server_addr;
1348                 i3.server_port = pipe_request->info.info2.server_port;
1349                 i3.sam_info3 = pipe_request->info.info2.sam_info3;
1350                 i3.session_key_length =
1351                                 pipe_request->info.info2.session_key_length;
1352                 i3.session_key = pipe_request->info.info2.session_key;
1353                 break;
1354
1355         case 3:
1356                 pipe_reply.level = 3;
1357                 pipe_reply.status = NT_STATUS_OK;
1358                 pipe_reply.info.info3.file_type = state->file_type;
1359                 pipe_reply.info.info3.device_state = state->device_state;
1360                 pipe_reply.info.info3.allocation_size = state->alloc_size;
1361
1362                 i3 = pipe_request->info.info3;
1363                 break;
1364
1365         default:
1366                 DEBUG(0, ("Unknown level %u\n", pipe_request->level));
1367                 pipe_reply.level = 0;
1368                 pipe_reply.status = NT_STATUS_INVALID_LEVEL;
1369                 goto reply;
1370         }
1371
1372         if (pipe_reply.level >=2) {
1373
1374                 if (i3.server_addr == NULL) {
1375                         pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1376                         DEBUG(2, ("Missing server address\n"));
1377                         goto reply;
1378                 }
1379                 if (i3.client_addr == NULL) {
1380                         pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1381                         DEBUG(2, ("Missing client address\n"));
1382                         goto reply;
1383                 }
1384
1385                 state->server_name = discard_const_p(char,
1386                                         talloc_move(state, &i3.server_name));
1387                 ret = tsocket_address_inet_from_strings(state, "ip",
1388                                                         i3.server_addr,
1389                                                         i3.server_port,
1390                                                         &state->server);
1391                 if (ret != 0) {
1392                         DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1393                                   i3.server_addr, i3.server_port,
1394                                   strerror(errno)));
1395                         pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1396                         goto reply;
1397                 }
1398
1399                 state->client_name = discard_const_p(char,
1400                                         talloc_move(state, &i3.client_name));
1401                 ret = tsocket_address_inet_from_strings(state, "ip",
1402                                                         i3.client_addr,
1403                                                         i3.client_port,
1404                                                         &state->client);
1405                 if (ret != 0) {
1406                         DEBUG(2, ("Invalid server address[%s:%u] - %s\n",
1407                                   i3.client_addr, i3.client_port,
1408                                   strerror(errno)));
1409                         pipe_reply.status = NT_STATUS_INVALID_ADDRESS;
1410                         goto reply;
1411                 }
1412
1413                 state->info3 = talloc_move(state, &i3.sam_info3);
1414                 state->session_key.data = talloc_move(state, &i3.session_key);
1415                 state->session_key.length = i3.session_key_length;
1416         }
1417
1418         if (pipe_reply.level >= 3) {
1419                 state->delegated_creds.data =
1420                         talloc_move(state, &i3.gssapi_delegated_creds);
1421                 state->delegated_creds.length =
1422                         i3.gssapi_delegated_creds_length;
1423         }
1424
1425 reply:
1426         /* create the output */
1427         ndr_err = ndr_push_struct_blob(&out, state, &pipe_reply,
1428                         (ndr_push_flags_fn_t)ndr_push_named_pipe_auth_rep);
1429         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1430                 DEBUG(2, ("Error encoding structure: %s",
1431                           ndr_map_error2string(ndr_err)));
1432                 tevent_req_error(req, EIO);
1433                 return;
1434         }
1435
1436         DEBUG(10, ("named_pipe_auth reply[%u]\n", (unsigned)out.length));
1437         dump_data(11, out.data, out.length);
1438
1439         if (DEBUGLVL(10)) {
1440                 NDR_PRINT_DEBUG(named_pipe_auth_rep, &pipe_reply);
1441         }
1442
1443         state->accept_status = pipe_reply.status;
1444
1445         state->out_iov.iov_base = out.data;
1446         state->out_iov.iov_len = out.length;
1447
1448         subreq = tstream_writev_send(state, state->ev,
1449                                      state->plain,
1450                                      &state->out_iov, 1);
1451         if (tevent_req_nomem(subreq, req)) {
1452                 DEBUG(0, ("no memory for tstream_writev_send"));
1453                 return;
1454         }
1455
1456         tevent_req_set_callback(subreq, tstream_npa_accept_existing_done, req);
1457 }
1458
1459 static void tstream_npa_accept_existing_done(struct tevent_req *subreq)
1460 {
1461         struct tevent_req *req =
1462                         tevent_req_callback_data(subreq, struct tevent_req);
1463         int sys_errno;
1464         int ret;
1465
1466         ret = tstream_writev_recv(subreq, &sys_errno);
1467         TALLOC_FREE(subreq);
1468         if (ret == -1) {
1469                 tevent_req_error(req, sys_errno);
1470                 return;
1471         }
1472
1473         tevent_req_done(req);
1474 }
1475
1476 int _tstream_npa_accept_existing_recv(struct tevent_req *req,
1477                                       int *perrno,
1478                                       TALLOC_CTX *mem_ctx,
1479                                       struct tstream_context **stream,
1480                                       struct tsocket_address **client,
1481                                       char **_client_name,
1482                                       struct tsocket_address **server,
1483                                       char **server_name,
1484                                       struct netr_SamInfo3 **info3,
1485                                       DATA_BLOB *session_key,
1486                                       DATA_BLOB *delegated_creds,
1487                                       const char *location)
1488 {
1489         struct tstream_npa_accept_state *state =
1490                         tevent_req_data(req, struct tstream_npa_accept_state);
1491         struct tstream_npa *npas;
1492         int ret;
1493
1494         ret = tsocket_simple_int_recv(req, perrno);
1495         if (ret != 0) {
1496                 DEBUG(2, ("Failed to accept named pipe conection: %s\n",
1497                           strerror(*perrno)));
1498                 tevent_req_received(req);
1499                 return -1;
1500         }
1501
1502         if (!NT_STATUS_IS_OK(state->accept_status)) {
1503 #if defined(EPROTONOSUPPORT)
1504                 *perrno = EPROTONOSUPPORT;
1505 #elif defined(EPROTO)
1506                 *perrno = EPROTO;
1507 #else
1508                 *perrno = EINVAL;
1509 #endif
1510                 DEBUG(2, ("Failed to accept named pipe conection: %s => %s\n",
1511                           nt_errstr(state->accept_status),
1512                           strerror(*perrno)));
1513                 tevent_req_received(req);
1514                 return -1;
1515         }
1516
1517         *stream = tstream_context_create(mem_ctx,
1518                                          &tstream_npa_ops,
1519                                          &npas,
1520                                          struct tstream_npa,
1521                                          location);
1522         if (!*stream) {
1523                 *perrno = ENOMEM;
1524                 tevent_req_received(req);
1525                 return -1;
1526         }
1527         ZERO_STRUCTP(npas);
1528         npas->unix_stream = state->plain;
1529         npas->file_type = state->file_type;
1530
1531         *client = talloc_move(mem_ctx, &state->client);
1532         *_client_name = talloc_move(mem_ctx, &state->client_name);
1533         *server = talloc_move(mem_ctx, &state->server);
1534         *server_name = talloc_move(mem_ctx, &state->server_name);
1535         *info3 = talloc_move(mem_ctx, &state->info3);
1536         *session_key = state->session_key;
1537         talloc_steal(mem_ctx, state->session_key.data);
1538         *delegated_creds = state->delegated_creds;
1539         talloc_steal(mem_ctx, state->delegated_creds.data);
1540
1541         tevent_req_received(req);
1542         return 0;
1543 }