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