LCOV - code coverage report
Current view: top level - source3/rpc_client - cli_pipe.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 1043 1522 68.5 %
Date: 2024-06-13 04:01:37 Functions: 74 78 94.9 %

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

Generated by: LCOV version 1.13