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