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