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