CVE-2015-5370: s3:rpc_client: protect rpc_api_pipe_got_pdu() against too large payloads
[metze/samba/wip.git] / source3 / rpc_client / cli_pipe.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client routines
4  *  Largely rewritten by Jeremy Allison             2005.
5  *  Heavily modified by Simo Sorce                  2010.
6  *  Copyright Andrew Bartlett                       2011.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "librpc/gen_ndr/ndr_epmapper_c.h"
25 #include "../librpc/gen_ndr/ndr_dssetup.h"
26 #include "../libcli/auth/schannel.h"
27 #include "../libcli/auth/netlogon_creds_cli.h"
28 #include "auth_generic.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "librpc/gen_ndr/ndr_netlogon_c.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "rpc_dce.h"
33 #include "cli_pipe.h"
34 #include "libsmb/libsmb.h"
35 #include "auth/gensec/gensec.h"
36 #include "auth/credentials/credentials.h"
37 #include "../libcli/smb/smbXcli_base.h"
38
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_RPC_CLI
41
42 /********************************************************************
43  Pipe description for a DEBUG
44  ********************************************************************/
45 static const char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx,
46                                    struct rpc_pipe_client *cli)
47 {
48         char *result = talloc_asprintf(mem_ctx, "host %s", cli->desthost);
49         if (result == NULL) {
50                 return "pipe";
51         }
52         return result;
53 }
54
55 /********************************************************************
56  Rpc pipe call id.
57  ********************************************************************/
58
59 static uint32_t get_rpc_call_id(void)
60 {
61         static uint32_t call_id = 0;
62         return ++call_id;
63 }
64
65 /*******************************************************************
66  Use SMBreadX to get rest of one fragment's worth of rpc data.
67  Reads the whole size or give an error message
68  ********************************************************************/
69
70 struct rpc_read_state {
71         struct tevent_context *ev;
72         struct rpc_cli_transport *transport;
73         uint8_t *data;
74         size_t size;
75         size_t num_read;
76 };
77
78 static void rpc_read_done(struct tevent_req *subreq);
79
80 static struct tevent_req *rpc_read_send(TALLOC_CTX *mem_ctx,
81                                         struct tevent_context *ev,
82                                         struct rpc_cli_transport *transport,
83                                         uint8_t *data, size_t size)
84 {
85         struct tevent_req *req, *subreq;
86         struct rpc_read_state *state;
87
88         req = tevent_req_create(mem_ctx, &state, struct rpc_read_state);
89         if (req == NULL) {
90                 return NULL;
91         }
92         state->ev = ev;
93         state->transport = transport;
94         state->data = data;
95         state->size = size;
96         state->num_read = 0;
97
98         DEBUG(5, ("rpc_read_send: data_to_read: %u\n", (unsigned int)size));
99
100         subreq = transport->read_send(state, ev, (uint8_t *)data, size,
101                                       transport->priv);
102         if (subreq == NULL) {
103                 goto fail;
104         }
105         tevent_req_set_callback(subreq, rpc_read_done, req);
106         return req;
107
108  fail:
109         TALLOC_FREE(req);
110         return NULL;
111 }
112
113 static void rpc_read_done(struct tevent_req *subreq)
114 {
115         struct tevent_req *req = tevent_req_callback_data(
116                 subreq, struct tevent_req);
117         struct rpc_read_state *state = tevent_req_data(
118                 req, struct rpc_read_state);
119         NTSTATUS status;
120         ssize_t received;
121
122         status = state->transport->read_recv(subreq, &received);
123         TALLOC_FREE(subreq);
124         if (!NT_STATUS_IS_OK(status)) {
125                 tevent_req_nterror(req, status);
126                 return;
127         }
128
129         state->num_read += received;
130         if (state->num_read == state->size) {
131                 tevent_req_done(req);
132                 return;
133         }
134
135         subreq = state->transport->read_send(state, state->ev,
136                                              state->data + state->num_read,
137                                              state->size - state->num_read,
138                                              state->transport->priv);
139         if (tevent_req_nomem(subreq, req)) {
140                 return;
141         }
142         tevent_req_set_callback(subreq, rpc_read_done, req);
143 }
144
145 static NTSTATUS rpc_read_recv(struct tevent_req *req)
146 {
147         return tevent_req_simple_recv_ntstatus(req);
148 }
149
150 struct rpc_write_state {
151         struct tevent_context *ev;
152         struct rpc_cli_transport *transport;
153         const uint8_t *data;
154         size_t size;
155         size_t num_written;
156 };
157
158 static void rpc_write_done(struct tevent_req *subreq);
159
160 static struct tevent_req *rpc_write_send(TALLOC_CTX *mem_ctx,
161                                          struct tevent_context *ev,
162                                          struct rpc_cli_transport *transport,
163                                          const uint8_t *data, size_t size)
164 {
165         struct tevent_req *req, *subreq;
166         struct rpc_write_state *state;
167
168         req = tevent_req_create(mem_ctx, &state, struct rpc_write_state);
169         if (req == NULL) {
170                 return NULL;
171         }
172         state->ev = ev;
173         state->transport = transport;
174         state->data = data;
175         state->size = size;
176         state->num_written = 0;
177
178         DEBUG(5, ("rpc_write_send: data_to_write: %u\n", (unsigned int)size));
179
180         subreq = transport->write_send(state, ev, data, size, transport->priv);
181         if (subreq == NULL) {
182                 goto fail;
183         }
184         tevent_req_set_callback(subreq, rpc_write_done, req);
185         return req;
186  fail:
187         TALLOC_FREE(req);
188         return NULL;
189 }
190
191 static void rpc_write_done(struct tevent_req *subreq)
192 {
193         struct tevent_req *req = tevent_req_callback_data(
194                 subreq, struct tevent_req);
195         struct rpc_write_state *state = tevent_req_data(
196                 req, struct rpc_write_state);
197         NTSTATUS status;
198         ssize_t written;
199
200         status = state->transport->write_recv(subreq, &written);
201         TALLOC_FREE(subreq);
202         if (!NT_STATUS_IS_OK(status)) {
203                 tevent_req_nterror(req, status);
204                 return;
205         }
206
207         state->num_written += written;
208
209         if (state->num_written == state->size) {
210                 tevent_req_done(req);
211                 return;
212         }
213
214         subreq = state->transport->write_send(state, state->ev,
215                                               state->data + state->num_written,
216                                               state->size - state->num_written,
217                                               state->transport->priv);
218         if (tevent_req_nomem(subreq, req)) {
219                 return;
220         }
221         tevent_req_set_callback(subreq, rpc_write_done, req);
222 }
223
224 static NTSTATUS rpc_write_recv(struct tevent_req *req)
225 {
226         return tevent_req_simple_recv_ntstatus(req);
227 }
228
229
230 /****************************************************************************
231  Try and get a PDU's worth of data from current_pdu. If not, then read more
232  from the wire.
233  ****************************************************************************/
234
235 struct get_complete_frag_state {
236         struct tevent_context *ev;
237         struct rpc_pipe_client *cli;
238         uint16_t frag_len;
239         DATA_BLOB *pdu;
240 };
241
242 static void get_complete_frag_got_header(struct tevent_req *subreq);
243 static void get_complete_frag_got_rest(struct tevent_req *subreq);
244
245 static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
246                                                  struct tevent_context *ev,
247                                                  struct rpc_pipe_client *cli,
248                                                  DATA_BLOB *pdu)
249 {
250         struct tevent_req *req, *subreq;
251         struct get_complete_frag_state *state;
252         size_t received;
253         NTSTATUS status;
254
255         req = tevent_req_create(mem_ctx, &state,
256                                 struct get_complete_frag_state);
257         if (req == NULL) {
258                 return NULL;
259         }
260         state->ev = ev;
261         state->cli = cli;
262         state->frag_len = RPC_HEADER_LEN;
263         state->pdu = pdu;
264
265         received = pdu->length;
266         if (received < RPC_HEADER_LEN) {
267                 if (!data_blob_realloc(mem_ctx, pdu, RPC_HEADER_LEN)) {
268                         status = NT_STATUS_NO_MEMORY;
269                         goto post_status;
270                 }
271                 subreq = rpc_read_send(state, state->ev,
272                                         state->cli->transport,
273                                         pdu->data + received,
274                                         RPC_HEADER_LEN - received);
275                 if (subreq == NULL) {
276                         status = NT_STATUS_NO_MEMORY;
277                         goto post_status;
278                 }
279                 tevent_req_set_callback(subreq, get_complete_frag_got_header,
280                                         req);
281                 return req;
282         }
283
284         state->frag_len = dcerpc_get_frag_length(pdu);
285         if (state->frag_len < RPC_HEADER_LEN) {
286                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
287                 return tevent_req_post(req, ev);
288         }
289
290         /*
291          * Ensure we have frag_len bytes of data.
292          */
293         if (received < state->frag_len) {
294                 if (!data_blob_realloc(NULL, pdu, state->frag_len)) {
295                         status = NT_STATUS_NO_MEMORY;
296                         goto post_status;
297                 }
298                 subreq = rpc_read_send(state, state->ev,
299                                         state->cli->transport,
300                                         pdu->data + received,
301                                         state->frag_len - received);
302                 if (subreq == NULL) {
303                         status = NT_STATUS_NO_MEMORY;
304                         goto post_status;
305                 }
306                 tevent_req_set_callback(subreq, get_complete_frag_got_rest,
307                                         req);
308                 return req;
309         }
310
311         status = NT_STATUS_OK;
312  post_status:
313         if (NT_STATUS_IS_OK(status)) {
314                 tevent_req_done(req);
315         } else {
316                 tevent_req_nterror(req, status);
317         }
318         return tevent_req_post(req, ev);
319 }
320
321 static void get_complete_frag_got_header(struct tevent_req *subreq)
322 {
323         struct tevent_req *req = tevent_req_callback_data(
324                 subreq, struct tevent_req);
325         struct get_complete_frag_state *state = tevent_req_data(
326                 req, struct get_complete_frag_state);
327         NTSTATUS status;
328
329         status = rpc_read_recv(subreq);
330         TALLOC_FREE(subreq);
331         if (!NT_STATUS_IS_OK(status)) {
332                 tevent_req_nterror(req, status);
333                 return;
334         }
335
336         state->frag_len = dcerpc_get_frag_length(state->pdu);
337         if (state->frag_len < RPC_HEADER_LEN) {
338                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
339                 return;
340         }
341
342         if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
343                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
344                 return;
345         }
346
347         /*
348          * We're here in this piece of code because we've read exactly
349          * RPC_HEADER_LEN bytes into state->pdu.
350          */
351
352         subreq = rpc_read_send(state, state->ev, state->cli->transport,
353                                 state->pdu->data + RPC_HEADER_LEN,
354                                 state->frag_len - RPC_HEADER_LEN);
355         if (tevent_req_nomem(subreq, req)) {
356                 return;
357         }
358         tevent_req_set_callback(subreq, get_complete_frag_got_rest, req);
359 }
360
361 static void get_complete_frag_got_rest(struct tevent_req *subreq)
362 {
363         struct tevent_req *req = tevent_req_callback_data(
364                 subreq, struct tevent_req);
365         NTSTATUS status;
366
367         status = rpc_read_recv(subreq);
368         TALLOC_FREE(subreq);
369         if (!NT_STATUS_IS_OK(status)) {
370                 tevent_req_nterror(req, status);
371                 return;
372         }
373         tevent_req_done(req);
374 }
375
376 static NTSTATUS get_complete_frag_recv(struct tevent_req *req)
377 {
378         return tevent_req_simple_recv_ntstatus(req);
379 }
380
381 /****************************************************************************
382  Do basic authentication checks on an incoming pdu.
383  ****************************************************************************/
384
385 static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
386                                                 struct rpc_pipe_client *cli,
387                                                 struct ncacn_packet *pkt,
388                                                 DATA_BLOB *pdu,
389                                                 uint8_t expected_pkt_type,
390                                                 uint32_t call_id,
391                                                 DATA_BLOB *rdata,
392                                                 DATA_BLOB *reply_pdu)
393 {
394         const struct dcerpc_response *r = NULL;
395         DATA_BLOB tmp_stub = data_blob_null;
396         NTSTATUS ret = NT_STATUS_OK;
397
398         /*
399          * Point the return values at the real data including the RPC
400          * header. Just in case the caller wants it.
401          */
402         *rdata = *pdu;
403
404         if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
405             !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
406                 /*
407                  * TODO: do we still need this hack which was introduced
408                  * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
409                  *
410                  * I don't even know what AS/U might be...
411                  */
412                 DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
413                           "fragment first/last ON.\n"));
414                 pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
415         }
416
417         /* Ensure we have the correct type. */
418         switch (pkt->ptype) {
419         case DCERPC_PKT_BIND_NAK:
420                 DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
421                           rpccli_pipe_txt(talloc_tos(), cli)));
422
423                 ret = dcerpc_verify_ncacn_packet_header(pkt,
424                                                 DCERPC_PKT_BIND_NAK,
425                                                 0, /* max_auth_info */
426                                                 DCERPC_PFC_FLAG_FIRST |
427                                                 DCERPC_PFC_FLAG_LAST,
428                                                 0); /* optional flags */
429                 if (!NT_STATUS_IS_OK(ret)) {
430                         DEBUG(1, (__location__ ": Connection to %s got an unexpected "
431                                   "RPC packet type - %u, expected %u: %s\n",
432                                   rpccli_pipe_txt(talloc_tos(), cli),
433                                   pkt->ptype, expected_pkt_type,
434                                   nt_errstr(ret)));
435                         NDR_PRINT_DEBUG(ncacn_packet, pkt);
436                         return ret;
437                 }
438
439                 /* Use this for now... */
440                 return NT_STATUS_NETWORK_ACCESS_DENIED;
441
442         case DCERPC_PKT_BIND_ACK:
443                 ret = dcerpc_verify_ncacn_packet_header(pkt,
444                                         expected_pkt_type,
445                                         pkt->u.bind_ack.auth_info.length,
446                                         DCERPC_PFC_FLAG_FIRST |
447                                         DCERPC_PFC_FLAG_LAST,
448                                         DCERPC_PFC_FLAG_CONC_MPX |
449                                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
450                 if (!NT_STATUS_IS_OK(ret)) {
451                         DEBUG(1, (__location__ ": Connection to %s got an unexpected "
452                                   "RPC packet type - %u, expected %u: %s\n",
453                                   rpccli_pipe_txt(talloc_tos(), cli),
454                                   pkt->ptype, expected_pkt_type,
455                                   nt_errstr(ret)));
456                         NDR_PRINT_DEBUG(ncacn_packet, pkt);
457                         return ret;
458                 }
459
460                 break;
461
462         case DCERPC_PKT_ALTER_RESP:
463                 ret = dcerpc_verify_ncacn_packet_header(pkt,
464                                         expected_pkt_type,
465                                         pkt->u.alter_resp.auth_info.length,
466                                         DCERPC_PFC_FLAG_FIRST |
467                                         DCERPC_PFC_FLAG_LAST,
468                                         DCERPC_PFC_FLAG_CONC_MPX |
469                                         DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
470                 if (!NT_STATUS_IS_OK(ret)) {
471                         DEBUG(1, (__location__ ": Connection to %s got an unexpected "
472                                   "RPC packet type - %u, expected %u: %s\n",
473                                   rpccli_pipe_txt(talloc_tos(), cli),
474                                   pkt->ptype, expected_pkt_type,
475                                   nt_errstr(ret)));
476                         NDR_PRINT_DEBUG(ncacn_packet, pkt);
477                         return ret;
478                 }
479
480                 break;
481
482         case DCERPC_PKT_RESPONSE:
483
484                 r = &pkt->u.response;
485
486                 ret = dcerpc_verify_ncacn_packet_header(pkt,
487                                                 expected_pkt_type,
488                                                 r->stub_and_verifier.length,
489                                                 0, /* required_flags */
490                                                 DCERPC_PFC_FLAG_FIRST |
491                                                 DCERPC_PFC_FLAG_LAST);
492                 if (!NT_STATUS_IS_OK(ret)) {
493                         DEBUG(1, (__location__ ": Connection to %s got an unexpected "
494                                   "RPC packet type - %u, expected %u: %s\n",
495                                   rpccli_pipe_txt(talloc_tos(), cli),
496                                   pkt->ptype, expected_pkt_type,
497                                   nt_errstr(ret)));
498                         NDR_PRINT_DEBUG(ncacn_packet, pkt);
499                         return ret;
500                 }
501
502                 tmp_stub.data = r->stub_and_verifier.data;
503                 tmp_stub.length = r->stub_and_verifier.length;
504
505                 /* Here's where we deal with incoming sign/seal. */
506                 ret = dcerpc_check_auth(cli->auth, pkt,
507                                         &tmp_stub,
508                                         DCERPC_RESPONSE_LENGTH,
509                                         pdu);
510                 if (!NT_STATUS_IS_OK(ret)) {
511                         DEBUG(1, (__location__ ": Connection to %s got an unexpected "
512                                   "RPC packet type - %u, expected %u: %s\n",
513                                   rpccli_pipe_txt(talloc_tos(), cli),
514                                   pkt->ptype, expected_pkt_type,
515                                   nt_errstr(ret)));
516                         NDR_PRINT_DEBUG(ncacn_packet, pkt);
517                         return ret;
518                 }
519
520                 /* Point the return values at the NDR data. */
521                 *rdata = tmp_stub;
522
523                 DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
524                            (long unsigned int)pdu->length,
525                            (long unsigned int)rdata->length));
526
527                 /*
528                  * If this is the first reply, and the allocation hint is
529                  * reasonable, try and set up the reply_pdu DATA_BLOB to the
530                  * correct size.
531                  */
532
533                 if ((reply_pdu->length == 0) &&
534                     r->alloc_hint && (r->alloc_hint < 15*1024*1024)) {
535                         if (!data_blob_realloc(mem_ctx, reply_pdu,
536                                                         r->alloc_hint)) {
537                                 DEBUG(0, ("reply alloc hint %d too "
538                                           "large to allocate\n",
539                                           (int)r->alloc_hint));
540                                 return NT_STATUS_NO_MEMORY;
541                         }
542                 }
543
544                 break;
545
546         case DCERPC_PKT_FAULT:
547
548                 ret = dcerpc_verify_ncacn_packet_header(pkt,
549                                                 DCERPC_PKT_FAULT,
550                                                 0, /* max_auth_info */
551                                                 DCERPC_PFC_FLAG_FIRST |
552                                                 DCERPC_PFC_FLAG_LAST,
553                                                 DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
554                 if (!NT_STATUS_IS_OK(ret)) {
555                         DEBUG(1, (__location__ ": Connection to %s got an unexpected "
556                                   "RPC packet type - %u, expected %u: %s\n",
557                                   rpccli_pipe_txt(talloc_tos(), cli),
558                                   pkt->ptype, expected_pkt_type,
559                                   nt_errstr(ret)));
560                         NDR_PRINT_DEBUG(ncacn_packet, pkt);
561                         return ret;
562                 }
563
564                 DEBUG(1, (__location__ ": RPC fault code %s received "
565                           "from %s!\n",
566                           dcerpc_errstr(talloc_tos(),
567                           pkt->u.fault.status),
568                           rpccli_pipe_txt(talloc_tos(), cli)));
569
570                 return dcerpc_fault_to_nt_status(pkt->u.fault.status);
571
572         default:
573                 DEBUG(0, (__location__ "Unknown packet type %u received "
574                           "from %s!\n",
575                           (unsigned int)pkt->ptype,
576                           rpccli_pipe_txt(talloc_tos(), cli)));
577                 return NT_STATUS_RPC_PROTOCOL_ERROR;
578         }
579
580
581         if (pkt->call_id != call_id) {
582                 DEBUG(3, (__location__ ": Connection to %s got an unexpected "
583                           "RPC call_id - %u, not %u\n",
584                           rpccli_pipe_txt(talloc_tos(), cli),
585                           pkt->call_id, call_id));
586                 return NT_STATUS_RPC_PROTOCOL_ERROR;
587         }
588
589         return NT_STATUS_OK;
590 }
591
592 /****************************************************************************
593  Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
594 ****************************************************************************/
595
596 struct cli_api_pipe_state {
597         struct tevent_context *ev;
598         struct rpc_cli_transport *transport;
599         uint8_t *rdata;
600         uint32_t rdata_len;
601 };
602
603 static void cli_api_pipe_trans_done(struct tevent_req *subreq);
604 static void cli_api_pipe_write_done(struct tevent_req *subreq);
605 static void cli_api_pipe_read_done(struct tevent_req *subreq);
606
607 static struct tevent_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
608                                             struct tevent_context *ev,
609                                             struct rpc_cli_transport *transport,
610                                             uint8_t *data, size_t data_len,
611                                             uint32_t max_rdata_len)
612 {
613         struct tevent_req *req, *subreq;
614         struct cli_api_pipe_state *state;
615         NTSTATUS status;
616
617         req = tevent_req_create(mem_ctx, &state, struct cli_api_pipe_state);
618         if (req == NULL) {
619                 return NULL;
620         }
621         state->ev = ev;
622         state->transport = transport;
623
624         if (max_rdata_len < RPC_HEADER_LEN) {
625                 /*
626                  * For a RPC reply we always need at least RPC_HEADER_LEN
627                  * bytes. We check this here because we will receive
628                  * RPC_HEADER_LEN bytes in cli_trans_sock_send_done.
629                  */
630                 status = NT_STATUS_INVALID_PARAMETER;
631                 goto post_status;
632         }
633
634         if (transport->trans_send != NULL) {
635                 subreq = transport->trans_send(state, ev, data, data_len,
636                                                max_rdata_len, transport->priv);
637                 if (subreq == NULL) {
638                         goto fail;
639                 }
640                 tevent_req_set_callback(subreq, cli_api_pipe_trans_done, req);
641                 return req;
642         }
643
644         /*
645          * If the transport does not provide a "trans" routine, i.e. for
646          * example the ncacn_ip_tcp transport, do the write/read step here.
647          */
648
649         subreq = rpc_write_send(state, ev, transport, data, data_len);
650         if (subreq == NULL) {
651                 goto fail;
652         }
653         tevent_req_set_callback(subreq, cli_api_pipe_write_done, req);
654         return req;
655
656  post_status:
657         tevent_req_nterror(req, status);
658         return tevent_req_post(req, ev);
659  fail:
660         TALLOC_FREE(req);
661         return NULL;
662 }
663
664 static void cli_api_pipe_trans_done(struct tevent_req *subreq)
665 {
666         struct tevent_req *req = tevent_req_callback_data(
667                 subreq, struct tevent_req);
668         struct cli_api_pipe_state *state = tevent_req_data(
669                 req, struct cli_api_pipe_state);
670         NTSTATUS status;
671
672         status = state->transport->trans_recv(subreq, state, &state->rdata,
673                                               &state->rdata_len);
674         TALLOC_FREE(subreq);
675         if (!NT_STATUS_IS_OK(status)) {
676                 tevent_req_nterror(req, status);
677                 return;
678         }
679         tevent_req_done(req);
680 }
681
682 static void cli_api_pipe_write_done(struct tevent_req *subreq)
683 {
684         struct tevent_req *req = tevent_req_callback_data(
685                 subreq, struct tevent_req);
686         struct cli_api_pipe_state *state = tevent_req_data(
687                 req, struct cli_api_pipe_state);
688         NTSTATUS status;
689
690         status = rpc_write_recv(subreq);
691         TALLOC_FREE(subreq);
692         if (!NT_STATUS_IS_OK(status)) {
693                 tevent_req_nterror(req, status);
694                 return;
695         }
696
697         state->rdata = talloc_array(state, uint8_t, RPC_HEADER_LEN);
698         if (tevent_req_nomem(state->rdata, req)) {
699                 return;
700         }
701
702         /*
703          * We don't need to use rpc_read_send here, the upper layer will cope
704          * with a short read, transport->trans_send could also return less
705          * than state->max_rdata_len.
706          */
707         subreq = state->transport->read_send(state, state->ev, state->rdata,
708                                              RPC_HEADER_LEN,
709                                              state->transport->priv);
710         if (tevent_req_nomem(subreq, req)) {
711                 return;
712         }
713         tevent_req_set_callback(subreq, cli_api_pipe_read_done, req);
714 }
715
716 static void cli_api_pipe_read_done(struct tevent_req *subreq)
717 {
718         struct tevent_req *req = tevent_req_callback_data(
719                 subreq, struct tevent_req);
720         struct cli_api_pipe_state *state = tevent_req_data(
721                 req, struct cli_api_pipe_state);
722         NTSTATUS status;
723         ssize_t received;
724
725         status = state->transport->read_recv(subreq, &received);
726         TALLOC_FREE(subreq);
727         if (!NT_STATUS_IS_OK(status)) {
728                 tevent_req_nterror(req, status);
729                 return;
730         }
731         state->rdata_len = received;
732         tevent_req_done(req);
733 }
734
735 static NTSTATUS cli_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
736                                   uint8_t **prdata, uint32_t *prdata_len)
737 {
738         struct cli_api_pipe_state *state = tevent_req_data(
739                 req, struct cli_api_pipe_state);
740         NTSTATUS status;
741
742         if (tevent_req_is_nterror(req, &status)) {
743                 return status;
744         }
745
746         *prdata = talloc_move(mem_ctx, &state->rdata);
747         *prdata_len = state->rdata_len;
748         return NT_STATUS_OK;
749 }
750
751 /****************************************************************************
752  Send data on an rpc pipe via trans. The data must be the last
753  pdu fragment of an NDR data stream.
754
755  Receive response data from an rpc pipe, which may be large...
756
757  Read the first fragment: unfortunately have to use SMBtrans for the first
758  bit, then SMBreadX for subsequent bits.
759
760  If first fragment received also wasn't the last fragment, continue
761  getting fragments until we _do_ receive the last fragment.
762
763  Request/Response PDU's look like the following...
764
765  |<------------------PDU len----------------------------------------------->|
766  |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
767
768  +------------+-----------------+-------------+---------------+-------------+
769  | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR      | AUTH DATA   |
770  +------------+-----------------+-------------+---------------+-------------+
771
772  Where the presence of the AUTH_HDR and AUTH DATA are dependent on the
773  signing & sealing being negotiated.
774
775  ****************************************************************************/
776
777 struct rpc_api_pipe_state {
778         struct tevent_context *ev;
779         struct rpc_pipe_client *cli;
780         uint8_t expected_pkt_type;
781         uint32_t call_id;
782
783         DATA_BLOB incoming_frag;
784         struct ncacn_packet *pkt;
785
786         /* Incoming reply */
787         DATA_BLOB reply_pdu;
788         size_t reply_pdu_offset;
789         uint8_t endianess;
790 };
791
792 static void rpc_api_pipe_trans_done(struct tevent_req *subreq);
793 static void rpc_api_pipe_got_pdu(struct tevent_req *subreq);
794 static void rpc_api_pipe_auth3_done(struct tevent_req *subreq);
795
796 static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
797                                             struct tevent_context *ev,
798                                             struct rpc_pipe_client *cli,
799                                             DATA_BLOB *data, /* Outgoing PDU */
800                                             uint8_t expected_pkt_type,
801                                             uint32_t call_id)
802 {
803         struct tevent_req *req, *subreq;
804         struct rpc_api_pipe_state *state;
805         uint16_t max_recv_frag;
806         NTSTATUS status;
807
808         req = tevent_req_create(mem_ctx, &state, struct rpc_api_pipe_state);
809         if (req == NULL) {
810                 return NULL;
811         }
812         state->ev = ev;
813         state->cli = cli;
814         state->expected_pkt_type = expected_pkt_type;
815         state->call_id = call_id;
816         state->endianess = DCERPC_DREP_LE;
817
818         /*
819          * Ensure we're not sending too much.
820          */
821         if (data->length > cli->max_xmit_frag) {
822                 status = NT_STATUS_INVALID_PARAMETER;
823                 goto post_status;
824         }
825
826         DEBUG(5,("rpc_api_pipe: %s\n", rpccli_pipe_txt(talloc_tos(), cli)));
827
828         if (state->expected_pkt_type == DCERPC_PKT_AUTH3) {
829                 subreq = rpc_write_send(state, ev, cli->transport,
830                                         data->data, data->length);
831                 if (subreq == NULL) {
832                         goto fail;
833                 }
834                 tevent_req_set_callback(subreq, rpc_api_pipe_auth3_done, req);
835                 return req;
836         }
837
838         /* get the header first, then fetch the rest once we have
839          * the frag_length available */
840         max_recv_frag = RPC_HEADER_LEN;
841
842         subreq = cli_api_pipe_send(state, ev, cli->transport,
843                                    data->data, data->length, max_recv_frag);
844         if (subreq == NULL) {
845                 goto fail;
846         }
847         tevent_req_set_callback(subreq, rpc_api_pipe_trans_done, req);
848         return req;
849
850  post_status:
851         tevent_req_nterror(req, status);
852         return tevent_req_post(req, ev);
853  fail:
854         TALLOC_FREE(req);
855         return NULL;
856 }
857
858 static void rpc_api_pipe_auth3_done(struct tevent_req *subreq)
859 {
860         struct tevent_req *req =
861                 tevent_req_callback_data(subreq,
862                 struct tevent_req);
863         NTSTATUS status;
864
865         status = rpc_write_recv(subreq);
866         TALLOC_FREE(subreq);
867         if (!NT_STATUS_IS_OK(status)) {
868                 tevent_req_nterror(req, status);
869                 return;
870         }
871
872         tevent_req_done(req);
873 }
874
875 static void rpc_api_pipe_trans_done(struct tevent_req *subreq)
876 {
877         struct tevent_req *req = tevent_req_callback_data(
878                 subreq, struct tevent_req);
879         struct rpc_api_pipe_state *state = tevent_req_data(
880                 req, struct rpc_api_pipe_state);
881         NTSTATUS status;
882         uint8_t *rdata = NULL;
883         uint32_t rdata_len = 0;
884
885         status = cli_api_pipe_recv(subreq, state, &rdata, &rdata_len);
886         TALLOC_FREE(subreq);
887         if (!NT_STATUS_IS_OK(status)) {
888                 DEBUG(5, ("cli_api_pipe failed: %s\n", nt_errstr(status)));
889                 tevent_req_nterror(req, status);
890                 return;
891         }
892
893         if (rdata == NULL) {
894                 DEBUG(3,("rpc_api_pipe: %s failed to return data.\n",
895                          rpccli_pipe_txt(talloc_tos(), state->cli)));
896                 tevent_req_done(req);
897                 return;
898         }
899
900         /*
901          * Move data on state->incoming_frag.
902          */
903         state->incoming_frag.data = talloc_move(state, &rdata);
904         state->incoming_frag.length = rdata_len;
905         if (!state->incoming_frag.data) {
906                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
907                 return;
908         }
909
910         /* Ensure we have enough data for a pdu. */
911         subreq = get_complete_frag_send(state, state->ev, state->cli,
912                                         &state->incoming_frag);
913         if (tevent_req_nomem(subreq, req)) {
914                 return;
915         }
916         tevent_req_set_callback(subreq, rpc_api_pipe_got_pdu, req);
917 }
918
919 static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
920 {
921         struct tevent_req *req = tevent_req_callback_data(
922                 subreq, struct tevent_req);
923         struct rpc_api_pipe_state *state = tevent_req_data(
924                 req, struct rpc_api_pipe_state);
925         NTSTATUS status;
926         DATA_BLOB rdata = data_blob_null;
927
928         status = get_complete_frag_recv(subreq);
929         TALLOC_FREE(subreq);
930         if (!NT_STATUS_IS_OK(status)) {
931                 DEBUG(5, ("get_complete_frag failed: %s\n",
932                           nt_errstr(status)));
933                 tevent_req_nterror(req, status);
934                 return;
935         }
936
937         state->pkt = talloc(state, struct ncacn_packet);
938         if (!state->pkt) {
939                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
940                 return;
941         }
942
943         status = dcerpc_pull_ncacn_packet(state->pkt,
944                                           &state->incoming_frag,
945                                           state->pkt,
946                                           !state->endianess);
947         if (!NT_STATUS_IS_OK(status)) {
948                 tevent_req_nterror(req, status);
949                 return;
950         }
951
952         status = cli_pipe_validate_current_pdu(state,
953                                                 state->cli, state->pkt,
954                                                 &state->incoming_frag,
955                                                 state->expected_pkt_type,
956                                                 state->call_id,
957                                                 &rdata,
958                                                 &state->reply_pdu);
959
960         DEBUG(10,("rpc_api_pipe: got frag len of %u at offset %u: %s\n",
961                   (unsigned)state->incoming_frag.length,
962                   (unsigned)state->reply_pdu_offset,
963                   nt_errstr(status)));
964
965         if (!NT_STATUS_IS_OK(status)) {
966                 tevent_req_nterror(req, status);
967                 return;
968         }
969
970         if ((state->pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)
971             && (state->pkt->drep[0] != DCERPC_DREP_LE)) {
972                 /*
973                  * Set the data type correctly for big-endian data on the
974                  * first packet.
975                  */
976                 DEBUG(10,("rpc_api_pipe: On %s PDU data format is "
977                           "big-endian.\n",
978                           rpccli_pipe_txt(talloc_tos(), state->cli)));
979                 state->endianess = 0x00; /* BIG ENDIAN */
980         }
981         /*
982          * Check endianness on subsequent packets.
983          */
984         if (state->endianess != state->pkt->drep[0]) {
985                 DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to "
986                          "%s\n",
987                          state->endianess?"little":"big",
988                          state->pkt->drep[0]?"little":"big"));
989                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
990                 return;
991         }
992
993         if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
994                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
995                 return;
996         }
997
998         /* Now copy the data portion out of the pdu into rbuf. */
999         if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
1000                 if (!data_blob_realloc(NULL, &state->reply_pdu,
1001                                 state->reply_pdu_offset + rdata.length)) {
1002                         tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1003                         return;
1004                 }
1005         }
1006
1007         memcpy(state->reply_pdu.data + state->reply_pdu_offset,
1008                 rdata.data, rdata.length);
1009         state->reply_pdu_offset += rdata.length;
1010
1011         /* reset state->incoming_frag, there is no need to free it,
1012          * it will be reallocated to the right size the next time
1013          * it is used */
1014         state->incoming_frag.length = 0;
1015
1016         if (state->pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1017                 /* make sure the pdu length is right now that we
1018                  * have all the data available (alloc hint may
1019                  * have allocated more than was actually used) */
1020                 state->reply_pdu.length = state->reply_pdu_offset;
1021                 DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n",
1022                           rpccli_pipe_txt(talloc_tos(), state->cli),
1023                           (unsigned)state->reply_pdu.length));
1024                 tevent_req_done(req);
1025                 return;
1026         }
1027
1028         subreq = get_complete_frag_send(state, state->ev, state->cli,
1029                                         &state->incoming_frag);
1030         if (tevent_req_nomem(subreq, req)) {
1031                 return;
1032         }
1033         tevent_req_set_callback(subreq, rpc_api_pipe_got_pdu, req);
1034 }
1035
1036 static NTSTATUS rpc_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1037                                   struct ncacn_packet **pkt,
1038                                   DATA_BLOB *reply_pdu)
1039 {
1040         struct rpc_api_pipe_state *state = tevent_req_data(
1041                 req, struct rpc_api_pipe_state);
1042         NTSTATUS status;
1043
1044         if (tevent_req_is_nterror(req, &status)) {
1045                 return status;
1046         }
1047
1048         /* return data to caller and assign it ownership of memory */
1049         if (reply_pdu) {
1050                 reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1051                 reply_pdu->length = state->reply_pdu.length;
1052                 state->reply_pdu.length = 0;
1053         } else {
1054                 data_blob_free(&state->reply_pdu);
1055         }
1056
1057         if (pkt) {
1058                 *pkt = talloc_steal(mem_ctx, state->pkt);
1059         }
1060
1061         return NT_STATUS_OK;
1062 }
1063
1064 /*******************************************************************
1065  Creates NTLMSSP auth bind.
1066  ********************************************************************/
1067
1068 static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
1069                                                  TALLOC_CTX *mem_ctx,
1070                                                  DATA_BLOB *auth_token,
1071                                                  bool *client_hdr_signing)
1072 {
1073         struct gensec_security *gensec_security;
1074         DATA_BLOB null_blob = data_blob_null;
1075         NTSTATUS status;
1076
1077         gensec_security = cli->auth->auth_ctx;
1078
1079         DEBUG(5, ("create_generic_auth_rpc_bind_req: generate first token\n"));
1080         status = gensec_update(gensec_security, mem_ctx, null_blob, auth_token);
1081
1082         if (!NT_STATUS_IS_OK(status) &&
1083             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
1084         {
1085                 return status;
1086         }
1087
1088         if (client_hdr_signing == NULL) {
1089                 return status;
1090         }
1091
1092         if (cli->auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1093                 *client_hdr_signing = false;
1094                 return status;
1095         }
1096
1097         *client_hdr_signing = gensec_have_feature(gensec_security,
1098                                                 GENSEC_FEATURE_SIGN_PKT_HEADER);
1099
1100         return status;
1101 }
1102
1103 /*******************************************************************
1104  Creates the internals of a DCE/RPC bind request or alter context PDU.
1105  ********************************************************************/
1106
1107 static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx,
1108                                                 enum dcerpc_pkt_type ptype,
1109                                                 uint32_t rpc_call_id,
1110                                                 const struct ndr_syntax_id *abstract,
1111                                                 const struct ndr_syntax_id *transfer,
1112                                                 const DATA_BLOB *auth_info,
1113                                                 bool client_hdr_signing,
1114                                                 DATA_BLOB *blob)
1115 {
1116         uint16_t auth_len = auth_info->length;
1117         NTSTATUS status;
1118         union dcerpc_payload u;
1119         struct dcerpc_ctx_list ctx_list;
1120         uint8_t pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1121
1122         if (auth_len) {
1123                 auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1124         }
1125
1126         if (client_hdr_signing) {
1127                 pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1128         }
1129
1130         ctx_list.context_id = 0;
1131         ctx_list.num_transfer_syntaxes = 1;
1132         ctx_list.abstract_syntax = *abstract;
1133         ctx_list.transfer_syntaxes = (struct ndr_syntax_id *)discard_const(transfer);
1134
1135         u.bind.max_xmit_frag    = RPC_MAX_PDU_FRAG_LEN;
1136         u.bind.max_recv_frag    = RPC_MAX_PDU_FRAG_LEN;
1137         u.bind.assoc_group_id   = 0x0;
1138         u.bind.num_contexts     = 1;
1139         u.bind.ctx_list         = &ctx_list;
1140         u.bind.auth_info        = *auth_info;
1141
1142         status = dcerpc_push_ncacn_packet(mem_ctx,
1143                                           ptype, pfc_flags,
1144                                           auth_len,
1145                                           rpc_call_id,
1146                                           &u,
1147                                           blob);
1148         if (!NT_STATUS_IS_OK(status)) {
1149                 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1150                 return status;
1151         }
1152
1153         return NT_STATUS_OK;
1154 }
1155
1156 /*******************************************************************
1157  Creates a DCE/RPC bind request.
1158  ********************************************************************/
1159
1160 static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
1161                                     struct rpc_pipe_client *cli,
1162                                     struct pipe_auth_data *auth,
1163                                     uint32_t rpc_call_id,
1164                                     const struct ndr_syntax_id *abstract,
1165                                     const struct ndr_syntax_id *transfer,
1166                                     DATA_BLOB *rpc_out)
1167 {
1168         DATA_BLOB auth_token = data_blob_null;
1169         DATA_BLOB auth_info = data_blob_null;
1170         NTSTATUS ret = NT_STATUS_OK;
1171
1172         switch (auth->auth_type) {
1173         case DCERPC_AUTH_TYPE_NONE:
1174                 break;
1175
1176         default:
1177                 ret = create_generic_auth_rpc_bind_req(cli, mem_ctx,
1178                                                        &auth_token,
1179                                                        &auth->client_hdr_signing);
1180
1181                 if (!NT_STATUS_IS_OK(ret) &&
1182                     !NT_STATUS_EQUAL(ret, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1183                         return ret;
1184                 }
1185                 break;
1186         }
1187
1188         if (auth_token.length != 0) {
1189                 ret = dcerpc_push_dcerpc_auth(cli,
1190                                                 auth->auth_type,
1191                                                 auth->auth_level,
1192                                                 0, /* auth_pad_length */
1193                                                 1, /* auth_context_id */
1194                                                 &auth_token,
1195                                                 &auth_info);
1196                 if (!NT_STATUS_IS_OK(ret)) {
1197                         return ret;
1198                 }
1199                 data_blob_free(&auth_token);
1200         }
1201
1202         ret = create_bind_or_alt_ctx_internal(mem_ctx,
1203                                               DCERPC_PKT_BIND,
1204                                               rpc_call_id,
1205                                               abstract,
1206                                               transfer,
1207                                               &auth_info,
1208                                               auth->client_hdr_signing,
1209                                               rpc_out);
1210         return ret;
1211 }
1212
1213 /*******************************************************************
1214  External interface.
1215  Does an rpc request on a pipe. Incoming data is NDR encoded in in_data.
1216  Reply is NDR encoded in out_data. Splits the data stream into RPC PDU's
1217  and deals with signing/sealing details.
1218  ********************************************************************/
1219
1220 struct rpc_api_pipe_req_state {
1221         struct tevent_context *ev;
1222         struct rpc_pipe_client *cli;
1223         uint8_t op_num;
1224         uint32_t call_id;
1225         const DATA_BLOB *req_data;
1226         uint32_t req_data_sent;
1227         DATA_BLOB req_trailer;
1228         uint32_t req_trailer_sent;
1229         bool verify_bitmask1;
1230         bool verify_pcontext;
1231         DATA_BLOB rpc_out;
1232         DATA_BLOB reply_pdu;
1233 };
1234
1235 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
1236 static void rpc_api_pipe_req_done(struct tevent_req *subreq);
1237 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
1238 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1239                                   bool *is_last_frag);
1240
1241 static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
1242                                          struct tevent_context *ev,
1243                                          struct rpc_pipe_client *cli,
1244                                          uint8_t op_num,
1245                                          const DATA_BLOB *req_data)
1246 {
1247         struct tevent_req *req, *subreq;
1248         struct rpc_api_pipe_req_state *state;
1249         NTSTATUS status;
1250         bool is_last_frag;
1251
1252         req = tevent_req_create(mem_ctx, &state,
1253                                 struct rpc_api_pipe_req_state);
1254         if (req == NULL) {
1255                 return NULL;
1256         }
1257         state->ev = ev;
1258         state->cli = cli;
1259         state->op_num = op_num;
1260         state->req_data = req_data;
1261         state->req_data_sent = 0;
1262         state->call_id = get_rpc_call_id();
1263         state->reply_pdu = data_blob_null;
1264         state->rpc_out = data_blob_null;
1265
1266         if (cli->max_xmit_frag < DCERPC_REQUEST_LENGTH
1267                                         + RPC_MAX_SIGN_SIZE) {
1268                 /* Server is screwed up ! */
1269                 status = NT_STATUS_INVALID_PARAMETER;
1270                 goto post_status;
1271         }
1272
1273         status = prepare_verification_trailer(state);
1274         if (!NT_STATUS_IS_OK(status)) {
1275                 goto post_status;
1276         }
1277
1278         status = prepare_next_frag(state, &is_last_frag);
1279         if (!NT_STATUS_IS_OK(status)) {
1280                 goto post_status;
1281         }
1282
1283         if (is_last_frag) {
1284                 subreq = rpc_api_pipe_send(state, ev, state->cli,
1285                                            &state->rpc_out,
1286                                            DCERPC_PKT_RESPONSE,
1287                                            state->call_id);
1288                 if (subreq == NULL) {
1289                         goto fail;
1290                 }
1291                 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1292         } else {
1293                 subreq = rpc_write_send(state, ev, cli->transport,
1294                                         state->rpc_out.data,
1295                                         state->rpc_out.length);
1296                 if (subreq == NULL) {
1297                         goto fail;
1298                 }
1299                 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1300                                         req);
1301         }
1302         return req;
1303
1304  post_status:
1305         tevent_req_nterror(req, status);
1306         return tevent_req_post(req, ev);
1307  fail:
1308         TALLOC_FREE(req);
1309         return NULL;
1310 }
1311
1312 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
1313 {
1314         struct pipe_auth_data *a = state->cli->auth;
1315         struct dcerpc_sec_verification_trailer *t;
1316         struct dcerpc_sec_vt *c = NULL;
1317         struct ndr_push *ndr = NULL;
1318         enum ndr_err_code ndr_err;
1319         size_t align = 0;
1320         size_t pad = 0;
1321
1322         if (a == NULL) {
1323                 return NT_STATUS_OK;
1324         }
1325
1326         if (a->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1327                 return NT_STATUS_OK;
1328         }
1329
1330         t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
1331         if (t == NULL) {
1332                 return NT_STATUS_NO_MEMORY;
1333         }
1334
1335         if (!a->verified_bitmask1) {
1336                 t->commands = talloc_realloc(t, t->commands,
1337                                              struct dcerpc_sec_vt,
1338                                              t->count.count + 1);
1339                 if (t->commands == NULL) {
1340                         return NT_STATUS_NO_MEMORY;
1341                 }
1342                 c = &t->commands[t->count.count++];
1343                 ZERO_STRUCTP(c);
1344
1345                 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1346                 if (a->client_hdr_signing) {
1347                         c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1348                 }
1349                 state->verify_bitmask1 = true;
1350         }
1351
1352         if (!state->cli->verified_pcontext) {
1353                 t->commands = talloc_realloc(t, t->commands,
1354                                              struct dcerpc_sec_vt,
1355                                              t->count.count + 1);
1356                 if (t->commands == NULL) {
1357                         return NT_STATUS_NO_MEMORY;
1358                 }
1359                 c = &t->commands[t->count.count++];
1360                 ZERO_STRUCTP(c);
1361
1362                 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1363                 c->u.pcontext.abstract_syntax = state->cli->abstract_syntax;
1364                 c->u.pcontext.transfer_syntax = state->cli->transfer_syntax;
1365
1366                 state->verify_pcontext = true;
1367         }
1368
1369         if (!a->hdr_signing) {
1370                 t->commands = talloc_realloc(t, t->commands,
1371                                              struct dcerpc_sec_vt,
1372                                              t->count.count + 1);
1373                 if (t->commands == NULL) {
1374                         return NT_STATUS_NO_MEMORY;
1375                 }
1376                 c = &t->commands[t->count.count++];
1377                 ZERO_STRUCTP(c);
1378
1379                 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1380                 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1381                 c->u.header2.drep[0] = DCERPC_DREP_LE;
1382                 c->u.header2.drep[1] = 0;
1383                 c->u.header2.drep[2] = 0;
1384                 c->u.header2.drep[3] = 0;
1385                 c->u.header2.call_id = state->call_id;
1386                 c->u.header2.context_id = 0;
1387                 c->u.header2.opnum = state->op_num;
1388         }
1389
1390         if (t->count.count == 0) {
1391                 TALLOC_FREE(t);
1392                 return NT_STATUS_OK;
1393         }
1394
1395         c = &t->commands[t->count.count - 1];
1396         c->command |= DCERPC_SEC_VT_COMMAND_END;
1397
1398         if (DEBUGLEVEL >= 10) {
1399                 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1400         }
1401
1402         ndr = ndr_push_init_ctx(state);
1403         if (ndr == NULL) {
1404                 return NT_STATUS_NO_MEMORY;
1405         }
1406
1407         ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1408                                                 NDR_SCALARS | NDR_BUFFERS,
1409                                                 t);
1410         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1411                 return ndr_map_error2ntstatus(ndr_err);
1412         }
1413         state->req_trailer = ndr_push_blob(ndr);
1414
1415         align = state->req_data->length & 0x3;
1416         if (align > 0) {
1417                 pad = 4 - align;
1418         }
1419         if (pad > 0) {
1420                 bool ok;
1421                 uint8_t *p;
1422                 const uint8_t zeros[4] = { 0, };
1423
1424                 ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
1425                 if (!ok) {
1426                         return NT_STATUS_NO_MEMORY;
1427                 }
1428
1429                 /* move the padding to the start */
1430                 p = state->req_trailer.data;
1431                 memmove(p + pad, p, state->req_trailer.length - pad);
1432                 memset(p, 0, pad);
1433         }
1434
1435         return NT_STATUS_OK;
1436 }
1437
1438 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1439                                   bool *is_last_frag)
1440 {
1441         size_t auth_len;
1442         size_t frag_len;
1443         uint8_t flags = 0;
1444         size_t pad_len;
1445         size_t data_left;
1446         size_t data_thistime;
1447         size_t trailer_left;
1448         size_t trailer_thistime = 0;
1449         size_t total_left;
1450         size_t total_thistime;
1451         NTSTATUS status;
1452         bool ok;
1453         union dcerpc_payload u;
1454
1455         data_left = state->req_data->length - state->req_data_sent;
1456         trailer_left = state->req_trailer.length - state->req_trailer_sent;
1457         total_left = data_left + trailer_left;
1458         if ((total_left < data_left) || (total_left < trailer_left)) {
1459                 /*
1460                  * overflow
1461                  */
1462                 return NT_STATUS_INVALID_PARAMETER_MIX;
1463         }
1464
1465         status = dcerpc_guess_sizes(state->cli->auth,
1466                                     DCERPC_REQUEST_LENGTH, total_left,
1467                                     state->cli->max_xmit_frag,
1468                                     &total_thistime,
1469                                     &frag_len, &auth_len, &pad_len);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 return status;
1472         }
1473
1474         if (state->req_data_sent == 0) {
1475                 flags = DCERPC_PFC_FLAG_FIRST;
1476         }
1477
1478         if (total_thistime == total_left) {
1479                 flags |= DCERPC_PFC_FLAG_LAST;
1480         }
1481
1482         data_thistime = MIN(total_thistime, data_left);
1483         if (data_thistime < total_thistime) {
1484                 trailer_thistime = total_thistime - data_thistime;
1485         }
1486
1487         data_blob_free(&state->rpc_out);
1488
1489         ZERO_STRUCT(u.request);
1490
1491         u.request.alloc_hint    = total_left;
1492         u.request.context_id    = 0;
1493         u.request.opnum         = state->op_num;
1494
1495         status = dcerpc_push_ncacn_packet(state,
1496                                           DCERPC_PKT_REQUEST,
1497                                           flags,
1498                                           auth_len,
1499                                           state->call_id,
1500                                           &u,
1501                                           &state->rpc_out);
1502         if (!NT_STATUS_IS_OK(status)) {
1503                 return status;
1504         }
1505
1506         /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1507          * compute it right for requests because the auth trailer is missing
1508          * at this stage */
1509         dcerpc_set_frag_length(&state->rpc_out, frag_len);
1510
1511         if (data_thistime > 0) {
1512                 /* Copy in the data. */
1513                 ok = data_blob_append(NULL, &state->rpc_out,
1514                                 state->req_data->data + state->req_data_sent,
1515                                 data_thistime);
1516                 if (!ok) {
1517                         return NT_STATUS_NO_MEMORY;
1518                 }
1519                 state->req_data_sent += data_thistime;
1520         }
1521
1522         if (trailer_thistime > 0) {
1523                 /* Copy in the verification trailer. */
1524                 ok = data_blob_append(NULL, &state->rpc_out,
1525                                 state->req_trailer.data + state->req_trailer_sent,
1526                                 trailer_thistime);
1527                 if (!ok) {
1528                         return NT_STATUS_NO_MEMORY;
1529                 }
1530                 state->req_trailer_sent += trailer_thistime;
1531         }
1532
1533         switch (state->cli->auth->auth_level) {
1534         case DCERPC_AUTH_LEVEL_NONE:
1535         case DCERPC_AUTH_LEVEL_CONNECT:
1536         case DCERPC_AUTH_LEVEL_PACKET:
1537                 break;
1538         case DCERPC_AUTH_LEVEL_INTEGRITY:
1539         case DCERPC_AUTH_LEVEL_PRIVACY:
1540                 status = dcerpc_add_auth_footer(state->cli->auth, pad_len,
1541                                                 &state->rpc_out);
1542                 if (!NT_STATUS_IS_OK(status)) {
1543                         return status;
1544                 }
1545                 break;
1546         default:
1547                 return NT_STATUS_INVALID_PARAMETER;
1548         }
1549
1550         *is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1551
1552         return status;
1553 }
1554
1555 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
1556 {
1557         struct tevent_req *req = tevent_req_callback_data(
1558                 subreq, struct tevent_req);
1559         struct rpc_api_pipe_req_state *state = tevent_req_data(
1560                 req, struct rpc_api_pipe_req_state);
1561         NTSTATUS status;
1562         bool is_last_frag;
1563
1564         status = rpc_write_recv(subreq);
1565         TALLOC_FREE(subreq);
1566         if (!NT_STATUS_IS_OK(status)) {
1567                 tevent_req_nterror(req, status);
1568                 return;
1569         }
1570
1571         status = prepare_next_frag(state, &is_last_frag);
1572         if (!NT_STATUS_IS_OK(status)) {
1573                 tevent_req_nterror(req, status);
1574                 return;
1575         }
1576
1577         if (is_last_frag) {
1578                 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
1579                                            &state->rpc_out,
1580                                            DCERPC_PKT_RESPONSE,
1581                                            state->call_id);
1582                 if (tevent_req_nomem(subreq, req)) {
1583                         return;
1584                 }
1585                 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1586         } else {
1587                 subreq = rpc_write_send(state, state->ev,
1588                                         state->cli->transport,
1589                                         state->rpc_out.data,
1590                                         state->rpc_out.length);
1591                 if (tevent_req_nomem(subreq, req)) {
1592                         return;
1593                 }
1594                 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1595                                         req);
1596         }
1597 }
1598
1599 static void rpc_api_pipe_req_done(struct tevent_req *subreq)
1600 {
1601         struct tevent_req *req = tevent_req_callback_data(
1602                 subreq, struct tevent_req);
1603         struct rpc_api_pipe_req_state *state = tevent_req_data(
1604                 req, struct rpc_api_pipe_req_state);
1605         NTSTATUS status;
1606
1607         status = rpc_api_pipe_recv(subreq, state, NULL, &state->reply_pdu);
1608         TALLOC_FREE(subreq);
1609         if (!NT_STATUS_IS_OK(status)) {
1610                 tevent_req_nterror(req, status);
1611                 return;
1612         }
1613
1614         if (state->cli->auth == NULL) {
1615                 tevent_req_done(req);
1616                 return;
1617         }
1618
1619         if (state->verify_bitmask1) {
1620                 state->cli->auth->verified_bitmask1 = true;
1621         }
1622
1623         if (state->verify_pcontext) {
1624                 state->cli->verified_pcontext = true;
1625         }
1626
1627         tevent_req_done(req);
1628 }
1629
1630 static NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1631                                DATA_BLOB *reply_pdu)
1632 {
1633         struct rpc_api_pipe_req_state *state = tevent_req_data(
1634                 req, struct rpc_api_pipe_req_state);
1635         NTSTATUS status;
1636
1637         if (tevent_req_is_nterror(req, &status)) {
1638                 /*
1639                  * We always have to initialize to reply pdu, even if there is
1640                  * none. The rpccli_* caller routines expect this.
1641                  */
1642                 *reply_pdu = data_blob_null;
1643                 return status;
1644         }
1645
1646         /* return data to caller and assign it ownership of memory */
1647         reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1648         reply_pdu->length = state->reply_pdu.length;
1649         state->reply_pdu.length = 0;
1650
1651         return NT_STATUS_OK;
1652 }
1653
1654 /****************************************************************************
1655  Check the rpc bind acknowledge response.
1656 ****************************************************************************/
1657
1658 static bool check_bind_response(const struct dcerpc_bind_ack *r,
1659                                 const struct ndr_syntax_id *transfer)
1660 {
1661         struct dcerpc_ack_ctx ctx;
1662
1663         if (r->secondary_address_size == 0) {
1664                 DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)"));
1665         }
1666
1667         if (r->num_results < 1 || !r->ctx_list) {
1668                 return false;
1669         }
1670
1671         ctx = r->ctx_list[0];
1672
1673         /* check the transfer syntax */
1674         if ((ctx.syntax.if_version != transfer->if_version) ||
1675              (memcmp(&ctx.syntax.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
1676                 DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
1677                 return False;
1678         }
1679
1680         if (r->num_results != 0x1 || ctx.result != 0) {
1681                 DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
1682                           r->num_results, ctx.reason.value));
1683         }
1684
1685         DEBUG(5,("check_bind_response: accepted!\n"));
1686         return True;
1687 }
1688
1689 /*******************************************************************
1690  Creates a DCE/RPC bind authentication response.
1691  This is the packet that is sent back to the server once we
1692  have received a BIND-ACK, to finish the third leg of
1693  the authentication handshake.
1694  ********************************************************************/
1695
1696 static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
1697                                 struct rpc_pipe_client *cli,
1698                                 uint32_t rpc_call_id,
1699                                 enum dcerpc_AuthType auth_type,
1700                                 enum dcerpc_AuthLevel auth_level,
1701                                 DATA_BLOB *pauth_blob,
1702                                 DATA_BLOB *rpc_out)
1703 {
1704         NTSTATUS status;
1705         union dcerpc_payload u;
1706
1707         u.auth3._pad = 0;
1708
1709         status = dcerpc_push_dcerpc_auth(mem_ctx,
1710                                          auth_type,
1711                                          auth_level,
1712                                          0, /* auth_pad_length */
1713                                          1, /* auth_context_id */
1714                                          pauth_blob,
1715                                          &u.auth3.auth_info);
1716         if (!NT_STATUS_IS_OK(status)) {
1717                 return status;
1718         }
1719
1720         status = dcerpc_push_ncacn_packet(mem_ctx,
1721                                           DCERPC_PKT_AUTH3,
1722                                           DCERPC_PFC_FLAG_FIRST |
1723                                           DCERPC_PFC_FLAG_LAST,
1724                                           pauth_blob->length,
1725                                           rpc_call_id,
1726                                           &u,
1727                                           rpc_out);
1728         data_blob_free(&u.auth3.auth_info);
1729         if (!NT_STATUS_IS_OK(status)) {
1730                 DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n"));
1731                 return status;
1732         }
1733
1734         return NT_STATUS_OK;
1735 }
1736
1737 /*******************************************************************
1738  Creates a DCE/RPC bind alter context authentication request which
1739  may contain a spnego auth blobl
1740  ********************************************************************/
1741
1742 static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
1743                                         enum dcerpc_AuthType auth_type,
1744                                         enum dcerpc_AuthLevel auth_level,
1745                                         uint32_t rpc_call_id,
1746                                         const struct ndr_syntax_id *abstract,
1747                                         const struct ndr_syntax_id *transfer,
1748                                         const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
1749                                         DATA_BLOB *rpc_out)
1750 {
1751         DATA_BLOB auth_info;
1752         NTSTATUS status;
1753
1754         status = dcerpc_push_dcerpc_auth(mem_ctx,
1755                                          auth_type,
1756                                          auth_level,
1757                                          0, /* auth_pad_length */
1758                                          1, /* auth_context_id */
1759                                          pauth_blob,
1760                                          &auth_info);
1761         if (!NT_STATUS_IS_OK(status)) {
1762                 return status;
1763         }
1764
1765         status = create_bind_or_alt_ctx_internal(mem_ctx,
1766                                                  DCERPC_PKT_ALTER,
1767                                                  rpc_call_id,
1768                                                  abstract,
1769                                                  transfer,
1770                                                  &auth_info,
1771                                                  false, /* client_hdr_signing */
1772                                                  rpc_out);
1773         data_blob_free(&auth_info);
1774         return status;
1775 }
1776
1777 /****************************************************************************
1778  Do an rpc bind.
1779 ****************************************************************************/
1780
1781 struct rpc_pipe_bind_state {
1782         struct tevent_context *ev;
1783         struct rpc_pipe_client *cli;
1784         DATA_BLOB rpc_out;
1785         bool auth3;
1786         uint32_t rpc_call_id;
1787 };
1788
1789 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq);
1790 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1791                                    struct rpc_pipe_bind_state *state,
1792                                    DATA_BLOB *credentials);
1793 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
1794                                      struct rpc_pipe_bind_state *state,
1795                                      DATA_BLOB *credentials);
1796
1797 struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
1798                                       struct tevent_context *ev,
1799                                       struct rpc_pipe_client *cli,
1800                                       struct pipe_auth_data *auth)
1801 {
1802         struct tevent_req *req, *subreq;
1803         struct rpc_pipe_bind_state *state;
1804         NTSTATUS status;
1805
1806         req = tevent_req_create(mem_ctx, &state, struct rpc_pipe_bind_state);
1807         if (req == NULL) {
1808                 return NULL;
1809         }
1810
1811         DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n",
1812                 rpccli_pipe_txt(talloc_tos(), cli),
1813                 (unsigned int)auth->auth_type,
1814                 (unsigned int)auth->auth_level ));
1815
1816         state->ev = ev;
1817         state->cli = cli;
1818         state->rpc_call_id = get_rpc_call_id();
1819
1820         cli->auth = talloc_move(cli, &auth);
1821
1822         /* Marshall the outgoing data. */
1823         status = create_rpc_bind_req(state, cli,
1824                                      cli->auth,
1825                                      state->rpc_call_id,
1826                                      &cli->abstract_syntax,
1827                                      &cli->transfer_syntax,
1828                                      &state->rpc_out);
1829
1830         if (!NT_STATUS_IS_OK(status) &&
1831             !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1832                 goto post_status;
1833         }
1834
1835         subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
1836                                    DCERPC_PKT_BIND_ACK, state->rpc_call_id);
1837         if (subreq == NULL) {
1838                 goto fail;
1839         }
1840         tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
1841         return req;
1842
1843  post_status:
1844         tevent_req_nterror(req, status);
1845         return tevent_req_post(req, ev);
1846  fail:
1847         TALLOC_FREE(req);
1848         return NULL;
1849 }
1850
1851 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
1852 {
1853         struct tevent_req *req = tevent_req_callback_data(
1854                 subreq, struct tevent_req);
1855         struct rpc_pipe_bind_state *state = tevent_req_data(
1856                 req, struct rpc_pipe_bind_state);
1857         struct pipe_auth_data *pauth = state->cli->auth;
1858         struct gensec_security *gensec_security;
1859         struct ncacn_packet *pkt = NULL;
1860         struct dcerpc_auth auth;
1861         DATA_BLOB auth_token = data_blob_null;
1862         NTSTATUS status;
1863
1864         status = rpc_api_pipe_recv(subreq, talloc_tos(), &pkt, NULL);
1865         TALLOC_FREE(subreq);
1866         if (!NT_STATUS_IS_OK(status)) {
1867                 DEBUG(3, ("rpc_pipe_bind: %s bind request returned %s\n",
1868                           rpccli_pipe_txt(talloc_tos(), state->cli),
1869                           nt_errstr(status)));
1870                 tevent_req_nterror(req, status);
1871                 return;
1872         }
1873
1874         if (state->auth3) {
1875                 tevent_req_done(req);
1876                 return;
1877         }
1878
1879         if (!check_bind_response(&pkt->u.bind_ack, &state->cli->transfer_syntax)) {
1880                 DEBUG(2, ("rpc_pipe_bind: check_bind_response failed.\n"));
1881                 tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
1882                 return;
1883         }
1884
1885         state->cli->max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1886         state->cli->max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1887
1888         switch(pauth->auth_type) {
1889
1890         case DCERPC_AUTH_TYPE_NONE:
1891                 /* Bind complete. */
1892                 tevent_req_done(req);
1893                 return;
1894
1895         default:
1896                 if (pkt->auth_length == 0) {
1897                         tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1898                         return;
1899                 }
1900
1901                 /* get auth credentials */
1902                 status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
1903                                                   &pkt->u.bind_ack.auth_info,
1904                                                   &auth, NULL, true);
1905                 if (!NT_STATUS_IS_OK(status)) {
1906                         DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
1907                                   nt_errstr(status)));
1908                         tevent_req_nterror(req, status);
1909                         return;
1910                 }
1911                 break;
1912         }
1913
1914         /*
1915          * For authenticated binds we may need to do 3 or 4 leg binds.
1916          */
1917
1918         switch(pauth->auth_type) {
1919
1920         case DCERPC_AUTH_TYPE_NONE:
1921                 /* Bind complete. */
1922                 tevent_req_done(req);
1923                 return;
1924
1925         default:
1926                 gensec_security = pauth->auth_ctx;
1927
1928                 if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
1929                         if (pauth->client_hdr_signing) {
1930                                 pauth->hdr_signing = true;
1931                                 gensec_want_feature(gensec_security,
1932                                                     GENSEC_FEATURE_SIGN_PKT_HEADER);
1933                         }
1934                 }
1935
1936                 status = gensec_update(gensec_security, state,
1937                                        auth.credentials, &auth_token);
1938                 if (NT_STATUS_EQUAL(status,
1939                                     NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1940                         status = rpc_bind_next_send(req, state,
1941                                                         &auth_token);
1942                 } else if (NT_STATUS_IS_OK(status)) {
1943                         if (auth_token.length == 0) {
1944                                 /* Bind complete. */
1945                                 tevent_req_done(req);
1946                                 return;
1947                         }
1948                         status = rpc_bind_finish_send(req, state,
1949                                                         &auth_token);
1950                 }
1951                 break;
1952         }
1953
1954         if (!NT_STATUS_IS_OK(status)) {
1955                 tevent_req_nterror(req, status);
1956         }
1957         return;
1958 }
1959
1960 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1961                                    struct rpc_pipe_bind_state *state,
1962                                    DATA_BLOB *auth_token)
1963 {
1964         struct pipe_auth_data *auth = state->cli->auth;
1965         struct tevent_req *subreq;
1966         NTSTATUS status;
1967
1968         /* Now prepare the alter context pdu. */
1969         data_blob_free(&state->rpc_out);
1970
1971         status = create_rpc_alter_context(state,
1972                                           auth->auth_type,
1973                                           auth->auth_level,
1974                                           state->rpc_call_id,
1975                                           &state->cli->abstract_syntax,
1976                                           &state->cli->transfer_syntax,
1977                                           auth_token,
1978                                           &state->rpc_out);
1979         if (!NT_STATUS_IS_OK(status)) {
1980                 return status;
1981         }
1982
1983         subreq = rpc_api_pipe_send(state, state->ev, state->cli,
1984                                    &state->rpc_out, DCERPC_PKT_ALTER_RESP,
1985                                    state->rpc_call_id);
1986         if (subreq == NULL) {
1987                 return NT_STATUS_NO_MEMORY;
1988         }
1989         tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
1990         return NT_STATUS_OK;
1991 }
1992
1993 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
1994                                      struct rpc_pipe_bind_state *state,
1995                                      DATA_BLOB *auth_token)
1996 {
1997         struct pipe_auth_data *auth = state->cli->auth;
1998         struct tevent_req *subreq;
1999         NTSTATUS status;
2000
2001         state->auth3 = true;
2002
2003         /* Now prepare the auth3 context pdu. */
2004         data_blob_free(&state->rpc_out);
2005
2006         status = create_rpc_bind_auth3(state, state->cli,
2007                                         state->rpc_call_id,
2008                                         auth->auth_type,
2009                                         auth->auth_level,
2010                                         auth_token,
2011                                         &state->rpc_out);
2012         if (!NT_STATUS_IS_OK(status)) {
2013                 return status;
2014         }
2015
2016         subreq = rpc_api_pipe_send(state, state->ev, state->cli,
2017                                    &state->rpc_out, DCERPC_PKT_AUTH3,
2018                                    state->rpc_call_id);
2019         if (subreq == NULL) {
2020                 return NT_STATUS_NO_MEMORY;
2021         }
2022         tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
2023         return NT_STATUS_OK;
2024 }
2025
2026 NTSTATUS rpc_pipe_bind_recv(struct tevent_req *req)
2027 {
2028         return tevent_req_simple_recv_ntstatus(req);
2029 }
2030
2031 NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
2032                        struct pipe_auth_data *auth)
2033 {
2034         TALLOC_CTX *frame = talloc_stackframe();
2035         struct tevent_context *ev;
2036         struct tevent_req *req;
2037         NTSTATUS status = NT_STATUS_OK;
2038
2039         ev = samba_tevent_context_init(frame);
2040         if (ev == NULL) {
2041                 status = NT_STATUS_NO_MEMORY;
2042                 goto fail;
2043         }
2044
2045         req = rpc_pipe_bind_send(frame, ev, cli, auth);
2046         if (req == NULL) {
2047                 status = NT_STATUS_NO_MEMORY;
2048                 goto fail;
2049         }
2050
2051         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2052                 goto fail;
2053         }
2054
2055         status = rpc_pipe_bind_recv(req);
2056  fail:
2057         TALLOC_FREE(frame);
2058         return status;
2059 }
2060
2061 #define RPCCLI_DEFAULT_TIMEOUT 10000 /* 10 seconds. */
2062
2063 unsigned int rpccli_set_timeout(struct rpc_pipe_client *rpc_cli,
2064                                 unsigned int timeout)
2065 {
2066         unsigned int old;
2067
2068         if (rpc_cli->transport == NULL) {
2069                 return RPCCLI_DEFAULT_TIMEOUT;
2070         }
2071
2072         if (rpc_cli->transport->set_timeout == NULL) {
2073                 return RPCCLI_DEFAULT_TIMEOUT;
2074         }
2075
2076         old = rpc_cli->transport->set_timeout(rpc_cli->transport->priv, timeout);
2077         if (old == 0) {
2078                 return RPCCLI_DEFAULT_TIMEOUT;
2079         }
2080
2081         return old;
2082 }
2083
2084 bool rpccli_is_connected(struct rpc_pipe_client *rpc_cli)
2085 {
2086         if (rpc_cli == NULL) {
2087                 return false;
2088         }
2089
2090         if (rpc_cli->transport == NULL) {
2091                 return false;
2092         }
2093
2094         return rpc_cli->transport->is_connected(rpc_cli->transport->priv);
2095 }
2096
2097 struct rpccli_bh_state {
2098         struct rpc_pipe_client *rpc_cli;
2099 };
2100
2101 static bool rpccli_bh_is_connected(struct dcerpc_binding_handle *h)
2102 {
2103         struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2104                                      struct rpccli_bh_state);
2105
2106         return rpccli_is_connected(hs->rpc_cli);
2107 }
2108
2109 static uint32_t rpccli_bh_set_timeout(struct dcerpc_binding_handle *h,
2110                                       uint32_t timeout)
2111 {
2112         struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2113                                      struct rpccli_bh_state);
2114
2115         return rpccli_set_timeout(hs->rpc_cli, timeout);
2116 }
2117
2118 static void rpccli_bh_auth_info(struct dcerpc_binding_handle *h,
2119                                 enum dcerpc_AuthType *auth_type,
2120                                 enum dcerpc_AuthLevel *auth_level)
2121 {
2122         struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2123                                      struct rpccli_bh_state);
2124
2125         if (hs->rpc_cli == NULL) {
2126                 return;
2127         }
2128
2129         if (hs->rpc_cli->auth == NULL) {
2130                 return;
2131         }
2132
2133         *auth_type = hs->rpc_cli->auth->auth_type;
2134         *auth_level = hs->rpc_cli->auth->auth_level;
2135 }
2136
2137 struct rpccli_bh_raw_call_state {
2138         DATA_BLOB in_data;
2139         DATA_BLOB out_data;
2140         uint32_t out_flags;
2141 };
2142
2143 static void rpccli_bh_raw_call_done(struct tevent_req *subreq);
2144
2145 static struct tevent_req *rpccli_bh_raw_call_send(TALLOC_CTX *mem_ctx,
2146                                                   struct tevent_context *ev,
2147                                                   struct dcerpc_binding_handle *h,
2148                                                   const struct GUID *object,
2149                                                   uint32_t opnum,
2150                                                   uint32_t in_flags,
2151                                                   const uint8_t *in_data,
2152                                                   size_t in_length)
2153 {
2154         struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2155                                      struct rpccli_bh_state);
2156         struct tevent_req *req;
2157         struct rpccli_bh_raw_call_state *state;
2158         bool ok;
2159         struct tevent_req *subreq;
2160
2161         req = tevent_req_create(mem_ctx, &state,
2162                                 struct rpccli_bh_raw_call_state);
2163         if (req == NULL) {
2164                 return NULL;
2165         }
2166         state->in_data.data = discard_const_p(uint8_t, in_data);
2167         state->in_data.length = in_length;
2168
2169         ok = rpccli_bh_is_connected(h);
2170         if (!ok) {
2171                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2172                 return tevent_req_post(req, ev);
2173         }
2174
2175         subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
2176                                        opnum, &state->in_data);
2177         if (tevent_req_nomem(subreq, req)) {
2178                 return tevent_req_post(req, ev);
2179         }
2180         tevent_req_set_callback(subreq, rpccli_bh_raw_call_done, req);
2181
2182         return req;
2183 }
2184
2185 static void rpccli_bh_raw_call_done(struct tevent_req *subreq)
2186 {
2187         struct tevent_req *req =
2188                 tevent_req_callback_data(subreq,
2189                 struct tevent_req);
2190         struct rpccli_bh_raw_call_state *state =
2191                 tevent_req_data(req,
2192                 struct rpccli_bh_raw_call_state);
2193         NTSTATUS status;
2194
2195         state->out_flags = 0;
2196
2197         /* TODO: support bigendian responses */
2198
2199         status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
2200         TALLOC_FREE(subreq);
2201         if (!NT_STATUS_IS_OK(status)) {
2202                 tevent_req_nterror(req, status);
2203                 return;
2204         }
2205
2206         tevent_req_done(req);
2207 }
2208
2209 static NTSTATUS rpccli_bh_raw_call_recv(struct tevent_req *req,
2210                                         TALLOC_CTX *mem_ctx,
2211                                         uint8_t **out_data,
2212                                         size_t *out_length,
2213                                         uint32_t *out_flags)
2214 {
2215         struct rpccli_bh_raw_call_state *state =
2216                 tevent_req_data(req,
2217                 struct rpccli_bh_raw_call_state);
2218         NTSTATUS status;
2219
2220         if (tevent_req_is_nterror(req, &status)) {
2221                 tevent_req_received(req);
2222                 return status;
2223         }
2224
2225         *out_data = talloc_move(mem_ctx, &state->out_data.data);
2226         *out_length = state->out_data.length;
2227         *out_flags = state->out_flags;
2228         tevent_req_received(req);
2229         return NT_STATUS_OK;
2230 }
2231
2232 struct rpccli_bh_disconnect_state {
2233         uint8_t _dummy;
2234 };
2235
2236 static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx,
2237                                                 struct tevent_context *ev,
2238                                                 struct dcerpc_binding_handle *h)
2239 {
2240         struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2241                                      struct rpccli_bh_state);
2242         struct tevent_req *req;
2243         struct rpccli_bh_disconnect_state *state;
2244         bool ok;
2245
2246         req = tevent_req_create(mem_ctx, &state,
2247                                 struct rpccli_bh_disconnect_state);
2248         if (req == NULL) {
2249                 return NULL;
2250         }
2251
2252         ok = rpccli_bh_is_connected(h);
2253         if (!ok) {
2254                 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2255                 return tevent_req_post(req, ev);
2256         }
2257
2258         /*
2259          * TODO: do a real async disconnect ...
2260          *
2261          * For now the caller needs to free rpc_cli
2262          */
2263         hs->rpc_cli = NULL;
2264
2265         tevent_req_done(req);
2266         return tevent_req_post(req, ev);
2267 }
2268
2269 static NTSTATUS rpccli_bh_disconnect_recv(struct tevent_req *req)
2270 {
2271         NTSTATUS status;
2272
2273         if (tevent_req_is_nterror(req, &status)) {
2274                 tevent_req_received(req);
2275                 return status;
2276         }
2277
2278         tevent_req_received(req);
2279         return NT_STATUS_OK;
2280 }
2281
2282 static bool rpccli_bh_ref_alloc(struct dcerpc_binding_handle *h)
2283 {
2284         return true;
2285 }
2286
2287 static void rpccli_bh_do_ndr_print(struct dcerpc_binding_handle *h,
2288                                    int ndr_flags,
2289                                    const void *_struct_ptr,
2290                                    const struct ndr_interface_call *call)
2291 {
2292         void *struct_ptr = discard_const(_struct_ptr);
2293
2294         if (DEBUGLEVEL < 10) {
2295                 return;
2296         }
2297
2298         if (ndr_flags & NDR_IN) {
2299                 ndr_print_function_debug(call->ndr_print,
2300                                          call->name,
2301                                          ndr_flags,
2302                                          struct_ptr);
2303         }
2304         if (ndr_flags & NDR_OUT) {
2305                 ndr_print_function_debug(call->ndr_print,
2306                                          call->name,
2307                                          ndr_flags,
2308                                          struct_ptr);
2309         }
2310 }
2311
2312 static const struct dcerpc_binding_handle_ops rpccli_bh_ops = {
2313         .name                   = "rpccli",
2314         .is_connected           = rpccli_bh_is_connected,
2315         .set_timeout            = rpccli_bh_set_timeout,
2316         .auth_info              = rpccli_bh_auth_info,
2317         .raw_call_send          = rpccli_bh_raw_call_send,
2318         .raw_call_recv          = rpccli_bh_raw_call_recv,
2319         .disconnect_send        = rpccli_bh_disconnect_send,
2320         .disconnect_recv        = rpccli_bh_disconnect_recv,
2321
2322         .ref_alloc              = rpccli_bh_ref_alloc,
2323         .do_ndr_print           = rpccli_bh_do_ndr_print,
2324 };
2325
2326 /* initialise a rpc_pipe_client binding handle */
2327 struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c,
2328                                         const struct GUID *object,
2329                                         const struct ndr_interface_table *table)
2330 {
2331         struct dcerpc_binding_handle *h;
2332         struct rpccli_bh_state *hs;
2333
2334         h = dcerpc_binding_handle_create(c,
2335                                          &rpccli_bh_ops,
2336                                          object,
2337                                          table,
2338                                          &hs,
2339                                          struct rpccli_bh_state,
2340                                          __location__);
2341         if (h == NULL) {
2342                 return NULL;
2343         }
2344         hs->rpc_cli = c;
2345
2346         return h;
2347 }
2348
2349 NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
2350                                struct pipe_auth_data **presult)
2351 {
2352         struct pipe_auth_data *result;
2353         struct auth_generic_state *auth_generic_ctx;
2354         NTSTATUS status;
2355
2356         result = talloc_zero(mem_ctx, struct pipe_auth_data);
2357         if (result == NULL) {
2358                 return NT_STATUS_NO_MEMORY;
2359         }
2360
2361         result->auth_type = DCERPC_AUTH_TYPE_NONE;
2362         result->auth_level = DCERPC_AUTH_LEVEL_NONE;
2363
2364         status = auth_generic_client_prepare(result,
2365                                              &auth_generic_ctx);
2366         if (!NT_STATUS_IS_OK(status)) {
2367                 DEBUG(1, ("Failed to create auth_generic context: %s\n",
2368                           nt_errstr(status)));
2369         }
2370
2371         status = auth_generic_set_username(auth_generic_ctx, "");
2372         if (!NT_STATUS_IS_OK(status)) {
2373                 DEBUG(1, ("Failed to set username: %s\n",
2374                           nt_errstr(status)));
2375         }
2376
2377         status = auth_generic_set_domain(auth_generic_ctx, "");
2378         if (!NT_STATUS_IS_OK(status)) {
2379                 DEBUG(1, ("Failed to set domain: %s\n",
2380                           nt_errstr(status)));
2381                 return status;
2382         }
2383
2384         status = gensec_set_credentials(auth_generic_ctx->gensec_security,
2385                                         auth_generic_ctx->credentials);
2386         if (!NT_STATUS_IS_OK(status)) {
2387                 DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
2388                           nt_errstr(status)));
2389                 return status;
2390         }
2391         talloc_unlink(auth_generic_ctx, auth_generic_ctx->credentials);
2392         auth_generic_ctx->credentials = NULL;
2393
2394         result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2395         talloc_free(auth_generic_ctx);
2396         *presult = result;
2397         return NT_STATUS_OK;
2398 }
2399
2400 static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
2401                                          enum dcerpc_AuthType auth_type,
2402                                          enum dcerpc_AuthLevel auth_level,
2403                                          const char *server,
2404                                          const char *target_service,
2405                                          const char *domain,
2406                                          const char *username,
2407                                          const char *password,
2408                                          enum credentials_use_kerberos use_kerberos,
2409                                          struct netlogon_creds_CredentialState *creds,
2410                                          struct pipe_auth_data **presult)
2411 {
2412         struct auth_generic_state *auth_generic_ctx;
2413         struct pipe_auth_data *result;
2414         NTSTATUS status;
2415
2416         result = talloc_zero(mem_ctx, struct pipe_auth_data);
2417         if (result == NULL) {
2418                 return NT_STATUS_NO_MEMORY;
2419         }
2420
2421         result->auth_type = auth_type;
2422         result->auth_level = auth_level;
2423
2424         status = auth_generic_client_prepare(result,
2425                                              &auth_generic_ctx);
2426         if (!NT_STATUS_IS_OK(status)) {
2427                 goto fail;
2428         }
2429
2430         status = auth_generic_set_username(auth_generic_ctx, username);
2431         if (!NT_STATUS_IS_OK(status)) {
2432                 goto fail;
2433         }
2434
2435         status = auth_generic_set_domain(auth_generic_ctx, domain);
2436         if (!NT_STATUS_IS_OK(status)) {
2437                 goto fail;
2438         }
2439
2440         status = auth_generic_set_password(auth_generic_ctx, password);
2441         if (!NT_STATUS_IS_OK(status)) {
2442                 goto fail;
2443         }
2444
2445         status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2446         if (!NT_STATUS_IS_OK(status)) {
2447                 goto fail;
2448         }
2449
2450         status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2451         if (!NT_STATUS_IS_OK(status)) {
2452                 goto fail;
2453         }
2454
2455         cli_credentials_set_kerberos_state(auth_generic_ctx->credentials, use_kerberos);
2456         cli_credentials_set_netlogon_creds(auth_generic_ctx->credentials, creds);
2457
2458         status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2459         if (!NT_STATUS_IS_OK(status)) {
2460                 goto fail;
2461         }
2462
2463         result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2464         talloc_free(auth_generic_ctx);
2465         *presult = result;
2466         return NT_STATUS_OK;
2467
2468  fail:
2469         TALLOC_FREE(result);
2470         return status;
2471 }
2472
2473 /* This routine steals the creds pointer that is passed in */
2474 static NTSTATUS rpccli_generic_bind_data_from_creds(TALLOC_CTX *mem_ctx,
2475                                                     enum dcerpc_AuthType auth_type,
2476                                                     enum dcerpc_AuthLevel auth_level,
2477                                                     const char *server,
2478                                                     const char *target_service,
2479                                                     struct cli_credentials *creds,
2480                                                     struct pipe_auth_data **presult)
2481 {
2482         struct auth_generic_state *auth_generic_ctx;
2483         struct pipe_auth_data *result;
2484         NTSTATUS status;
2485
2486         result = talloc_zero(mem_ctx, struct pipe_auth_data);
2487         if (result == NULL) {
2488                 return NT_STATUS_NO_MEMORY;
2489         }
2490
2491         result->auth_type = auth_type;
2492         result->auth_level = auth_level;
2493
2494         status = auth_generic_client_prepare(result,
2495                                              &auth_generic_ctx);
2496         if (!NT_STATUS_IS_OK(status)) {
2497                 goto fail;
2498         }
2499
2500         status = auth_generic_set_creds(auth_generic_ctx, creds);
2501         if (!NT_STATUS_IS_OK(status)) {
2502                 goto fail;
2503         }
2504
2505         status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2506         if (!NT_STATUS_IS_OK(status)) {
2507                 goto fail;
2508         }
2509
2510         status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2511         if (!NT_STATUS_IS_OK(status)) {
2512                 goto fail;
2513         }
2514
2515         status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2516         if (!NT_STATUS_IS_OK(status)) {
2517                 goto fail;
2518         }
2519
2520         result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2521         talloc_free(auth_generic_ctx);
2522         *presult = result;
2523         return NT_STATUS_OK;
2524
2525  fail:
2526         TALLOC_FREE(result);
2527         return status;
2528 }
2529
2530 NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
2531                                   struct pipe_auth_data **presult)
2532 {
2533         return rpccli_generic_bind_data(mem_ctx,
2534                                         DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
2535                                         DCERPC_AUTH_LEVEL_CONNECT,
2536                                         NULL, /* server */
2537                                         "host", /* target_service */
2538                                         NAME_NT_AUTHORITY, /* domain */
2539                                         "SYSTEM",
2540                                         "", /* password */
2541                                         CRED_DONT_USE_KERBEROS,
2542                                         NULL, /* netlogon_creds_CredentialState */
2543                                         presult);
2544 }
2545
2546 /**
2547  * Create an rpc pipe client struct, connecting to a tcp port.
2548  */
2549 static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
2550                                        const struct sockaddr_storage *ss_addr,
2551                                        uint16_t port,
2552                                        const struct ndr_interface_table *table,
2553                                        struct rpc_pipe_client **presult)
2554 {
2555         struct rpc_pipe_client *result;
2556         struct sockaddr_storage addr;
2557         NTSTATUS status;
2558         int fd;
2559
2560         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2561         if (result == NULL) {
2562                 return NT_STATUS_NO_MEMORY;
2563         }
2564
2565         result->abstract_syntax = table->syntax_id;
2566         result->transfer_syntax = ndr_transfer_syntax_ndr;
2567
2568         result->desthost = talloc_strdup(result, host);
2569         result->srv_name_slash = talloc_asprintf_strupper_m(
2570                 result, "\\\\%s", result->desthost);
2571         if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
2572                 status = NT_STATUS_NO_MEMORY;
2573                 goto fail;
2574         }
2575
2576         result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2577         result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
2578
2579         if (ss_addr == NULL) {
2580                 if (!resolve_name(host, &addr, NBT_NAME_SERVER, false)) {
2581                         status = NT_STATUS_NOT_FOUND;
2582                         goto fail;
2583                 }
2584         } else {
2585                 addr = *ss_addr;
2586         }
2587
2588         status = open_socket_out(&addr, port, 60*1000, &fd);
2589         if (!NT_STATUS_IS_OK(status)) {
2590                 goto fail;
2591         }
2592         set_socket_options(fd, lp_socket_options());
2593
2594         status = rpc_transport_sock_init(result, fd, &result->transport);
2595         if (!NT_STATUS_IS_OK(status)) {
2596                 close(fd);
2597                 goto fail;
2598         }
2599
2600         result->transport->transport = NCACN_IP_TCP;
2601
2602         result->binding_handle = rpccli_bh_create(result, NULL, table);
2603         if (result->binding_handle == NULL) {
2604                 TALLOC_FREE(result);
2605                 return NT_STATUS_NO_MEMORY;
2606         }
2607
2608         *presult = result;
2609         return NT_STATUS_OK;
2610
2611  fail:
2612         TALLOC_FREE(result);
2613         return status;
2614 }
2615
2616 /**
2617  * Determine the tcp port on which a dcerpc interface is listening
2618  * for the ncacn_ip_tcp transport via the endpoint mapper of the
2619  * target host.
2620  */
2621 static NTSTATUS rpc_pipe_get_tcp_port(const char *host,
2622                                       const struct sockaddr_storage *addr,
2623                                       const struct ndr_interface_table *table,
2624                                       uint16_t *pport)
2625 {
2626         NTSTATUS status;
2627         struct rpc_pipe_client *epm_pipe = NULL;
2628         struct dcerpc_binding_handle *epm_handle = NULL;
2629         struct pipe_auth_data *auth = NULL;
2630         struct dcerpc_binding *map_binding = NULL;
2631         struct dcerpc_binding *res_binding = NULL;
2632         enum dcerpc_transport_t transport;
2633         const char *endpoint = NULL;
2634         struct epm_twr_t *map_tower = NULL;
2635         struct epm_twr_t *res_towers = NULL;
2636         struct policy_handle *entry_handle = NULL;
2637         uint32_t num_towers = 0;
2638         uint32_t max_towers = 1;
2639         struct epm_twr_p_t towers;
2640         TALLOC_CTX *tmp_ctx = talloc_stackframe();
2641         uint32_t result = 0;
2642
2643         if (pport == NULL) {
2644                 status = NT_STATUS_INVALID_PARAMETER;
2645                 goto done;
2646         }
2647
2648         if (ndr_syntax_id_equal(&table->syntax_id,
2649                                 &ndr_table_epmapper.syntax_id)) {
2650                 *pport = 135;
2651                 status = NT_STATUS_OK;
2652                 goto done;
2653         }
2654
2655         /* open the connection to the endpoint mapper */
2656         status = rpc_pipe_open_tcp_port(tmp_ctx, host, addr, 135,
2657                                         &ndr_table_epmapper,
2658                                         &epm_pipe);
2659
2660         if (!NT_STATUS_IS_OK(status)) {
2661                 goto done;
2662         }
2663         epm_handle = epm_pipe->binding_handle;
2664
2665         status = rpccli_anon_bind_data(tmp_ctx, &auth);
2666         if (!NT_STATUS_IS_OK(status)) {
2667                 goto done;
2668         }
2669
2670         status = rpc_pipe_bind(epm_pipe, auth);
2671         if (!NT_STATUS_IS_OK(status)) {
2672                 goto done;
2673         }
2674
2675         /* create tower for asking the epmapper */
2676
2677         status = dcerpc_parse_binding(tmp_ctx, "ncacn_ip_tcp:[135]",
2678                                       &map_binding);
2679         if (!NT_STATUS_IS_OK(status)) {
2680                 goto done;
2681         }
2682
2683         status = dcerpc_binding_set_abstract_syntax(map_binding,
2684                                                     &table->syntax_id);
2685         if (!NT_STATUS_IS_OK(status)) {
2686                 goto done;
2687         }
2688
2689         map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
2690         if (map_tower == NULL) {
2691                 status = NT_STATUS_NO_MEMORY;
2692                 goto done;
2693         }
2694
2695         status = dcerpc_binding_build_tower(tmp_ctx, map_binding,
2696                                             &(map_tower->tower));
2697         if (!NT_STATUS_IS_OK(status)) {
2698                 goto done;
2699         }
2700
2701         /* allocate further parameters for the epm_Map call */
2702
2703         res_towers = talloc_array(tmp_ctx, struct epm_twr_t, max_towers);
2704         if (res_towers == NULL) {
2705                 status = NT_STATUS_NO_MEMORY;
2706                 goto done;
2707         }
2708         towers.twr = res_towers;
2709
2710         entry_handle = talloc_zero(tmp_ctx, struct policy_handle);
2711         if (entry_handle == NULL) {
2712                 status = NT_STATUS_NO_MEMORY;
2713                 goto done;
2714         }
2715
2716         /* ask the endpoint mapper for the port */
2717
2718         status = dcerpc_epm_Map(epm_handle,
2719                                 tmp_ctx,
2720                                 discard_const_p(struct GUID,
2721                                               &(table->syntax_id.uuid)),
2722                                 map_tower,
2723                                 entry_handle,
2724                                 max_towers,
2725                                 &num_towers,
2726                                 &towers,
2727                                 &result);
2728
2729         if (!NT_STATUS_IS_OK(status)) {
2730                 goto done;
2731         }
2732
2733         if (result != EPMAPPER_STATUS_OK) {
2734                 status = NT_STATUS_UNSUCCESSFUL;
2735                 goto done;
2736         }
2737
2738         if (num_towers != 1) {
2739                 status = NT_STATUS_UNSUCCESSFUL;
2740                 goto done;
2741         }
2742
2743         /* extract the port from the answer */
2744
2745         status = dcerpc_binding_from_tower(tmp_ctx,
2746                                            &(towers.twr->tower),
2747                                            &res_binding);
2748         if (!NT_STATUS_IS_OK(status)) {
2749                 goto done;
2750         }
2751
2752         transport = dcerpc_binding_get_transport(res_binding);
2753         endpoint = dcerpc_binding_get_string_option(res_binding, "endpoint");
2754
2755         /* are further checks here necessary? */
2756         if (transport != NCACN_IP_TCP) {
2757                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2758                 goto done;
2759         }
2760
2761         if (endpoint == NULL) {
2762                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2763                 goto done;
2764         }
2765
2766         *pport = (uint16_t)atoi(endpoint);
2767
2768 done:
2769         TALLOC_FREE(tmp_ctx);
2770         return status;
2771 }
2772
2773 /**
2774  * Create a rpc pipe client struct, connecting to a host via tcp.
2775  * The port is determined by asking the endpoint mapper on the given
2776  * host.
2777  */
2778 NTSTATUS rpc_pipe_open_tcp(TALLOC_CTX *mem_ctx, const char *host,
2779                            const struct sockaddr_storage *addr,
2780                            const struct ndr_interface_table *table,
2781                            struct rpc_pipe_client **presult)
2782 {
2783         NTSTATUS status;
2784         uint16_t port = 0;
2785
2786         status = rpc_pipe_get_tcp_port(host, addr, table, &port);
2787         if (!NT_STATUS_IS_OK(status)) {
2788                 return status;
2789         }
2790
2791         return rpc_pipe_open_tcp_port(mem_ctx, host, addr, port,
2792                                       table, presult);
2793 }
2794
2795 /********************************************************************
2796  Create a rpc pipe client struct, connecting to a unix domain socket
2797  ********************************************************************/
2798 NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
2799                                const struct ndr_interface_table *table,
2800                                struct rpc_pipe_client **presult)
2801 {
2802         struct rpc_pipe_client *result;
2803         struct sockaddr_un addr;
2804         NTSTATUS status;
2805         int fd;
2806         socklen_t salen;
2807
2808         result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2809         if (result == NULL) {
2810                 return NT_STATUS_NO_MEMORY;
2811         }
2812
2813         result->abstract_syntax = table->syntax_id;
2814         result->transfer_syntax = ndr_transfer_syntax_ndr;
2815
2816         result->desthost = get_myname(result);
2817         result->srv_name_slash = talloc_asprintf_strupper_m(
2818                 result, "\\\\%s", result->desthost);
2819         if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
2820                 status = NT_STATUS_NO_MEMORY;
2821                 goto fail;
2822         }
2823
2824         result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2825         result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
2826
2827         fd = socket(AF_UNIX, SOCK_STREAM, 0);
2828         if (fd == -1) {
2829                 status = map_nt_error_from_unix(errno);
2830                 goto fail;
2831         }
2832
2833         ZERO_STRUCT(addr);
2834         addr.sun_family = AF_UNIX;
2835         strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
2836         salen = sizeof(struct sockaddr_un);
2837
2838         if (connect(fd, (struct sockaddr *)(void *)&addr, salen) == -1) {
2839                 DEBUG(0, ("connect(%s) failed: %s\n", socket_path,
2840                           strerror(errno)));
2841                 close(fd);
2842                 return map_nt_error_from_unix(errno);
2843         }
2844
2845         status = rpc_transport_sock_init(result, fd, &result->transport);
2846         if (!NT_STATUS_IS_OK(status)) {
2847                 close(fd);
2848                 goto fail;
2849         }
2850
2851         result->transport->transport = NCALRPC;
2852
2853         result->binding_handle = rpccli_bh_create(result, NULL, table);
2854         if (result->binding_handle == NULL) {
2855                 TALLOC_FREE(result);
2856                 return NT_STATUS_NO_MEMORY;
2857         }
2858
2859         *presult = result;
2860         return NT_STATUS_OK;
2861
2862  fail:
2863         TALLOC_FREE(result);
2864         return status;
2865 }
2866
2867 struct rpc_pipe_client_np_ref {
2868         struct cli_state *cli;
2869         struct rpc_pipe_client *pipe;
2870 };
2871
2872 static int rpc_pipe_client_np_ref_destructor(struct rpc_pipe_client_np_ref *np_ref)
2873 {
2874         DLIST_REMOVE(np_ref->cli->pipe_list, np_ref->pipe);
2875         return 0;
2876 }
2877
2878 /****************************************************************************
2879  Open a named pipe over SMB to a remote server.
2880  *
2881  * CAVEAT CALLER OF THIS FUNCTION:
2882  *    The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
2883  *    so be sure that this function is called AFTER any structure (vs pointer)
2884  *    assignment of the cli.  In particular, libsmbclient does structure
2885  *    assignments of cli, which invalidates the data in the returned
2886  *    rpc_pipe_client if this function is called before the structure assignment
2887  *    of cli.
2888  * 
2889  ****************************************************************************/
2890
2891 static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
2892                                  const struct ndr_interface_table *table,
2893                                  struct rpc_pipe_client **presult)
2894 {
2895         struct rpc_pipe_client *result;
2896         NTSTATUS status;
2897         struct rpc_pipe_client_np_ref *np_ref;
2898
2899         /* sanity check to protect against crashes */
2900
2901         if ( !cli ) {
2902                 return NT_STATUS_INVALID_HANDLE;
2903         }
2904
2905         result = talloc_zero(NULL, struct rpc_pipe_client);
2906         if (result == NULL) {
2907                 return NT_STATUS_NO_MEMORY;
2908         }
2909
2910         result->abstract_syntax = table->syntax_id;
2911         result->transfer_syntax = ndr_transfer_syntax_ndr;
2912         result->desthost = talloc_strdup(result, smbXcli_conn_remote_name(cli->conn));
2913         result->srv_name_slash = talloc_asprintf_strupper_m(
2914                 result, "\\\\%s", result->desthost);
2915
2916         result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2917         result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
2918
2919         if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
2920                 TALLOC_FREE(result);
2921                 return NT_STATUS_NO_MEMORY;
2922         }
2923
2924         status = rpc_transport_np_init(result, cli, table,
2925                                        &result->transport);
2926         if (!NT_STATUS_IS_OK(status)) {
2927                 TALLOC_FREE(result);
2928                 return status;
2929         }
2930
2931         result->transport->transport = NCACN_NP;
2932
2933         np_ref = talloc(result->transport, struct rpc_pipe_client_np_ref);
2934         if (np_ref == NULL) {
2935                 TALLOC_FREE(result);
2936                 return NT_STATUS_NO_MEMORY;
2937         }
2938         np_ref->cli = cli;
2939         np_ref->pipe = result;
2940
2941         DLIST_ADD(np_ref->cli->pipe_list, np_ref->pipe);
2942         talloc_set_destructor(np_ref, rpc_pipe_client_np_ref_destructor);
2943
2944         result->binding_handle = rpccli_bh_create(result, NULL, table);
2945         if (result->binding_handle == NULL) {
2946                 TALLOC_FREE(result);
2947                 return NT_STATUS_NO_MEMORY;
2948         }
2949
2950         *presult = result;
2951         return NT_STATUS_OK;
2952 }
2953
2954 /****************************************************************************
2955  Open a pipe to a remote server.
2956  ****************************************************************************/
2957
2958 static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli,
2959                                   enum dcerpc_transport_t transport,
2960                                   const struct ndr_interface_table *table,
2961                                   struct rpc_pipe_client **presult)
2962 {
2963         switch (transport) {
2964         case NCACN_IP_TCP:
2965                 return rpc_pipe_open_tcp(NULL,
2966                                          smbXcli_conn_remote_name(cli->conn),
2967                                          smbXcli_conn_remote_sockaddr(cli->conn),
2968                                          table, presult);
2969         case NCACN_NP:
2970                 return rpc_pipe_open_np(cli, table, presult);
2971         default:
2972                 return NT_STATUS_NOT_IMPLEMENTED;
2973         }
2974 }
2975
2976 /****************************************************************************
2977  Open a named pipe to an SMB server and bind anonymously.
2978  ****************************************************************************/
2979
2980 NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
2981                                             enum dcerpc_transport_t transport,
2982                                             const struct ndr_interface_table *table,
2983                                             struct rpc_pipe_client **presult)
2984 {
2985         struct rpc_pipe_client *result;
2986         struct pipe_auth_data *auth;
2987         NTSTATUS status;
2988
2989         status = cli_rpc_pipe_open(cli, transport, table, &result);
2990         if (!NT_STATUS_IS_OK(status)) {
2991                 return status;
2992         }
2993
2994         status = rpccli_anon_bind_data(result, &auth);
2995         if (!NT_STATUS_IS_OK(status)) {
2996                 DEBUG(0, ("rpccli_anon_bind_data returned %s\n",
2997                           nt_errstr(status)));
2998                 TALLOC_FREE(result);
2999                 return status;
3000         }
3001
3002         /*
3003          * This is a bit of an abstraction violation due to the fact that an
3004          * anonymous bind on an authenticated SMB inherits the user/domain
3005          * from the enclosing SMB creds
3006          */
3007
3008         if (transport == NCACN_NP) {
3009                 struct smbXcli_session *session;
3010
3011                 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3012                         session = cli->smb2.session;
3013                 } else {
3014                         session = cli->smb1.session;
3015                 }
3016
3017                 status = smbXcli_session_application_key(session, auth,
3018                                                 &auth->transport_session_key);
3019                 if (!NT_STATUS_IS_OK(status)) {
3020                         auth->transport_session_key = data_blob_null;
3021                 }
3022         }
3023
3024         status = rpc_pipe_bind(result, auth);
3025         if (!NT_STATUS_IS_OK(status)) {
3026                 int lvl = 0;
3027                 if (ndr_syntax_id_equal(&table->syntax_id,
3028                                         &ndr_table_dssetup.syntax_id)) {
3029                         /* non AD domains just don't have this pipe, avoid
3030                          * level 0 statement in that case - gd */
3031                         lvl = 3;
3032                 }
3033                 DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
3034                             "%s failed with error %s\n",
3035                             table->name,
3036                             nt_errstr(status) ));
3037                 TALLOC_FREE(result);
3038                 return status;
3039         }
3040
3041         DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
3042                   "%s and bound anonymously.\n",
3043                   table->name,
3044                   result->desthost));
3045
3046         *presult = result;
3047         return NT_STATUS_OK;
3048 }
3049
3050 /****************************************************************************
3051  ****************************************************************************/
3052
3053 NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
3054                                   const struct ndr_interface_table *table,
3055                                   struct rpc_pipe_client **presult)
3056 {
3057         return cli_rpc_pipe_open_noauth_transport(cli, NCACN_NP,
3058                                                   table, presult);
3059 }
3060
3061 /****************************************************************************
3062  Open a named pipe to an SMB server and bind using the mech specified
3063
3064  This routine references the creds pointer that is passed in
3065  ****************************************************************************/
3066
3067 NTSTATUS cli_rpc_pipe_open_with_creds(struct cli_state *cli,
3068                                       const struct ndr_interface_table *table,
3069                                       enum dcerpc_transport_t transport,
3070                                       enum dcerpc_AuthType auth_type,
3071                                       enum dcerpc_AuthLevel auth_level,
3072                                       const char *server,
3073                                       struct cli_credentials *creds,
3074                                       struct rpc_pipe_client **presult)
3075 {
3076         struct rpc_pipe_client *result;
3077         struct pipe_auth_data *auth = NULL;
3078         const char *target_service = table->authservices->names[0];
3079
3080         NTSTATUS status;
3081
3082         status = cli_rpc_pipe_open(cli, transport, table, &result);
3083         if (!NT_STATUS_IS_OK(status)) {
3084                 return status;
3085         }
3086
3087         status = rpccli_generic_bind_data_from_creds(result,
3088                                                      auth_type, auth_level,
3089                                                      server, target_service,
3090                                                      creds,
3091                                                      &auth);
3092         if (!NT_STATUS_IS_OK(status)) {
3093                 DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
3094                           nt_errstr(status)));
3095                 goto err;
3096         }
3097
3098         status = rpc_pipe_bind(result, auth);
3099         if (!NT_STATUS_IS_OK(status)) {
3100                 DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
3101                         nt_errstr(status) ));
3102                 goto err;
3103         }
3104
3105         DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
3106                 "machine %s and bound as user %s.\n", table->name,
3107                   result->desthost, cli_credentials_get_unparsed_name(creds, talloc_tos())));
3108
3109         *presult = result;
3110         return NT_STATUS_OK;
3111
3112   err:
3113
3114         TALLOC_FREE(result);
3115         return status;
3116 }
3117
3118 /****************************************************************************
3119  Open a named pipe to an SMB server and bind using the mech specified
3120
3121  This routine steals the creds pointer that is passed in
3122  ****************************************************************************/
3123
3124 NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
3125                                         const struct ndr_interface_table *table,
3126                                         enum dcerpc_transport_t transport,
3127                                         enum credentials_use_kerberos use_kerberos,
3128                                         enum dcerpc_AuthType auth_type,
3129                                         enum dcerpc_AuthLevel auth_level,
3130                                         const char *server,
3131                                         const char *domain,
3132                                         const char *username,
3133                                         const char *password,
3134                                         struct rpc_pipe_client **presult)
3135 {
3136         struct rpc_pipe_client *result;
3137         struct pipe_auth_data *auth = NULL;
3138         const char *target_service = table->authservices->names[0];
3139         
3140         NTSTATUS status;
3141
3142         status = cli_rpc_pipe_open(cli, transport, table, &result);
3143         if (!NT_STATUS_IS_OK(status)) {
3144                 return status;
3145         }
3146
3147         status = rpccli_generic_bind_data(result,
3148                                           auth_type, auth_level,
3149                                           server, target_service,
3150                                           domain, username, password, 
3151                                           CRED_AUTO_USE_KERBEROS,
3152                                           NULL,
3153                                           &auth);
3154         if (!NT_STATUS_IS_OK(status)) {
3155                 DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
3156                           nt_errstr(status)));
3157                 goto err;
3158         }
3159
3160         status = rpc_pipe_bind(result, auth);
3161         if (!NT_STATUS_IS_OK(status)) {
3162                 DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
3163                         nt_errstr(status) ));
3164                 goto err;
3165         }
3166
3167         DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
3168                 "machine %s and bound as user %s\\%s.\n", table->name,
3169                   result->desthost, domain, username));
3170
3171         *presult = result;
3172         return NT_STATUS_OK;
3173
3174   err:
3175
3176         TALLOC_FREE(result);
3177         return status;
3178 }
3179
3180 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
3181                                                const struct ndr_interface_table *table,
3182                                                enum dcerpc_transport_t transport,
3183                                                struct cli_credentials *cli_creds,
3184                                                struct netlogon_creds_cli_context *netlogon_creds,
3185                                                struct rpc_pipe_client **_rpccli)
3186 {
3187         struct rpc_pipe_client *rpccli;
3188         struct pipe_auth_data *rpcauth;
3189         const char *target_service = table->authservices->names[0];
3190         struct netlogon_creds_CredentialState *ncreds = NULL;
3191         enum dcerpc_AuthLevel auth_level;
3192         NTSTATUS status;
3193         int rpc_pipe_bind_dbglvl = 0;
3194
3195         status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
3196         if (!NT_STATUS_IS_OK(status)) {
3197                 return status;
3198         }
3199
3200         status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &ncreds);
3201         if (!NT_STATUS_IS_OK(status)) {
3202                 DEBUG(0, ("netlogon_creds_cli_get returned %s\n",
3203                           nt_errstr(status)));
3204                 TALLOC_FREE(rpccli);
3205                 return status;
3206         }
3207
3208         auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
3209
3210         cli_credentials_set_netlogon_creds(cli_creds, ncreds);
3211
3212         status = rpccli_generic_bind_data_from_creds(rpccli,
3213                                                      DCERPC_AUTH_TYPE_SCHANNEL,
3214                                                      auth_level,
3215                                                      rpccli->desthost,
3216                                                      target_service,
3217                                                      cli_creds,
3218                                                      &rpcauth);
3219         if (!NT_STATUS_IS_OK(status)) {
3220                 DEBUG(0, ("rpccli_generic_bind_data_from_creds returned %s\n",
3221                           nt_errstr(status)));
3222                 TALLOC_FREE(rpccli);
3223                 return status;
3224         }
3225
3226         status = rpc_pipe_bind(rpccli, rpcauth);
3227         cli_credentials_set_netlogon_creds(cli_creds, NULL);
3228         if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
3229                 rpc_pipe_bind_dbglvl = 1;
3230                 netlogon_creds_cli_delete(netlogon_creds, &ncreds);
3231         }
3232         if (!NT_STATUS_IS_OK(status)) {
3233                 DEBUG(rpc_pipe_bind_dbglvl,
3234                       ("%s: rpc_pipe_bind failed with error %s\n",
3235                        __func__, nt_errstr(status)));
3236                 TALLOC_FREE(rpccli);
3237                 return status;
3238         }
3239
3240         TALLOC_FREE(ncreds);
3241
3242         if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
3243                 goto done;
3244         }
3245
3246         status = netlogon_creds_cli_check(netlogon_creds,
3247                                           rpccli->binding_handle);
3248         if (!NT_STATUS_IS_OK(status)) {
3249                 DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
3250                           nt_errstr(status)));
3251                 TALLOC_FREE(rpccli);
3252                 return status;
3253         }
3254
3255
3256 done:
3257         DEBUG(10,("%s: opened pipe %s to machine %s "
3258                   "for domain %s and bound using schannel.\n",
3259                   __func__, table->name,
3260                   rpccli->desthost, cli_credentials_get_domain(cli_creds)));
3261
3262         *_rpccli = rpccli;
3263         return NT_STATUS_OK;
3264 }
3265
3266 NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
3267                              struct rpc_pipe_client *cli,
3268                              DATA_BLOB *session_key)
3269 {
3270         NTSTATUS status;
3271         struct pipe_auth_data *a;
3272         struct gensec_security *gensec_security;
3273         DATA_BLOB sk = data_blob_null;
3274         bool make_dup = false;
3275
3276         if (!session_key || !cli) {
3277                 return NT_STATUS_INVALID_PARAMETER;
3278         }
3279
3280         a = cli->auth;
3281
3282         if (a == NULL) {
3283                 return NT_STATUS_INVALID_PARAMETER;
3284         }
3285
3286         switch (cli->auth->auth_type) {
3287         case DCERPC_AUTH_TYPE_NONE:
3288                 sk = data_blob_const(a->transport_session_key.data,
3289                                      a->transport_session_key.length);
3290                 make_dup = true;
3291                 break;
3292         default:
3293                 gensec_security = a->auth_ctx;
3294                 status = gensec_session_key(gensec_security, mem_ctx, &sk);
3295                 if (!NT_STATUS_IS_OK(status)) {
3296                         return status;
3297                 }
3298                 make_dup = false;
3299                 break;
3300         }
3301
3302         if (!sk.data) {
3303                 return NT_STATUS_NO_USER_SESSION_KEY;
3304         }
3305
3306         if (make_dup) {
3307                 *session_key = data_blob_dup_talloc(mem_ctx, sk);
3308         } else {
3309                 *session_key = sk;
3310         }
3311
3312         return NT_STATUS_OK;
3313 }