s3-dcerpc: Use DATA_BLOB instead of prs_struct for incoming fragments
authorSimo Sorce <idra@samba.org>
Wed, 14 Jul 2010 22:29:32 +0000 (18:29 -0400)
committerGünther Deschner <gd@samba.org>
Thu, 15 Jul 2010 23:51:17 +0000 (01:51 +0200)
Signed-off-by: Günther Deschner <gd@samba.org>
source3/rpc_client/cli_pipe.c

index 005f19307e462fa681092f48d35a04a8f1190b58..ce38f965c57ca3fc3993fd8da7e296bf90d19c27 100644 (file)
@@ -270,31 +270,6 @@ static uint32 get_rpc_call_id(void)
        return ++call_id;
 }
 
-/*
- * Realloc pdu to have a least "size" bytes
- */
-
-static bool rpc_grow_buffer(prs_struct *pdu, size_t size)
-{
-       size_t extra_size;
-
-       if (prs_data_size(pdu) >= size) {
-               return true;
-       }
-
-       extra_size = size - prs_data_size(pdu);
-
-       if (!prs_force_grow(pdu, extra_size)) {
-               DEBUG(0, ("rpc_grow_buffer: Failed to grow parse struct by "
-                         "%d bytes.\n", (int)extra_size));
-               return false;
-       }
-
-       DEBUG(5, ("rpc_grow_buffer: grew buffer by %d bytes to %u\n",
-                 (int)extra_size, prs_data_size(pdu)));
-       return true;
-}
-
 /*******************************************************************
  Use SMBreadX to get rest of one fragment's worth of rpc data.
  Reads the whole size or give an error message
@@ -469,7 +444,7 @@ struct get_complete_frag_state {
        struct event_context *ev;
        struct rpc_pipe_client *cli;
        uint16_t frag_len;
-       prs_struct *pdu;
+       DATA_BLOB *pdu;
 };
 
 static void get_complete_frag_got_header(struct tevent_req *subreq);
@@ -478,12 +453,11 @@ static void get_complete_frag_got_rest(struct tevent_req *subreq);
 static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
                                                 struct event_context *ev,
                                                 struct rpc_pipe_client *cli,
-                                                prs_struct *pdu)
+                                                DATA_BLOB *pdu)
 {
        struct tevent_req *req, *subreq;
        struct get_complete_frag_state *state;
-       DATA_BLOB blob;
-       uint32_t pdu_len;
+       size_t received;
        NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &state,
@@ -496,17 +470,16 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
        state->frag_len = RPC_HEADER_LEN;
        state->pdu = pdu;
 
-       pdu_len = prs_data_size(pdu);
-       if (pdu_len < RPC_HEADER_LEN) {
-               if (!rpc_grow_buffer(pdu, RPC_HEADER_LEN)) {
+       received = pdu->length;
+       if (received < RPC_HEADER_LEN) {
+               if (!data_blob_realloc(mem_ctx, pdu, RPC_HEADER_LEN)) {
                        status = NT_STATUS_NO_MEMORY;
                        goto post_status;
                }
-               subreq = rpc_read_send(
-                       state, state->ev,
-                       state->cli->transport,
-                       (uint8_t *)(prs_data_p(state->pdu) + pdu_len),
-                       RPC_HEADER_LEN - pdu_len);
+               subreq = rpc_read_send(state, state->ev,
+                                       state->cli->transport,
+                                       pdu->data + received,
+                                       RPC_HEADER_LEN - received);
                if (subreq == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto post_status;
@@ -516,21 +489,20 @@ static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
                return req;
        }
 
-       blob = data_blob_const(prs_data_p(state->pdu), pdu_len);
-       state->frag_len = dcerpc_get_frag_length(&blob);
+       state->frag_len = dcerpc_get_frag_length(pdu);
 
        /*
         * Ensure we have frag_len bytes of data.
         */
-       if (pdu_len < state->frag_len) {
-               if (!rpc_grow_buffer(pdu, state->frag_len)) {
+       if (received < state->frag_len) {
+               if (!data_blob_realloc(NULL, pdu, state->frag_len)) {
                        status = NT_STATUS_NO_MEMORY;
                        goto post_status;
                }
                subreq = rpc_read_send(state, state->ev,
-                                      state->cli->transport,
-                                      (uint8_t *)(prs_data_p(pdu) + pdu_len),
-                                      state->frag_len - pdu_len);
+                                       state->cli->transport,
+                                       pdu->data + received,
+                                       state->frag_len - received);
                if (subreq == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto post_status;
@@ -557,7 +529,6 @@ static void get_complete_frag_got_header(struct tevent_req *subreq)
        struct get_complete_frag_state *state = tevent_req_data(
                req, struct get_complete_frag_state);
        NTSTATUS status;
-       DATA_BLOB pdu;
 
        status = rpc_read_recv(subreq);
        TALLOC_FREE(subreq);
@@ -566,11 +537,9 @@ static void get_complete_frag_got_header(struct tevent_req *subreq)
                return;
        }
 
-       pdu = data_blob_const(prs_data_p(state->pdu),
-                             prs_data_size(state->pdu));
-       state->frag_len = dcerpc_get_frag_length(&pdu);
+       state->frag_len = dcerpc_get_frag_length(state->pdu);
 
-       if (!rpc_grow_buffer(state->pdu, state->frag_len)) {
+       if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
                tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
@@ -580,10 +549,9 @@ static void get_complete_frag_got_header(struct tevent_req *subreq)
         * RPC_HEADER_LEN bytes into state->pdu.
         */
 
-       subreq = rpc_read_send(
-               state, state->ev, state->cli->transport,
-               (uint8_t *)(prs_data_p(state->pdu) + RPC_HEADER_LEN),
-               state->frag_len - RPC_HEADER_LEN);
+       subreq = rpc_read_send(state, state->ev, state->cli->transport,
+                               state->pdu->data + RPC_HEADER_LEN,
+                               state->frag_len - RPC_HEADER_LEN);
        if (tevent_req_nomem(subreq, req)) {
                return;
        }
@@ -618,10 +586,9 @@ static NTSTATUS get_complete_frag_recv(struct tevent_req *req)
 
 static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli,
                                        struct ncacn_packet *pkt,
-                                       prs_struct *current_pdu,
+                                       DATA_BLOB *pdu,
                                        uint8 *p_ss_padding_len)
 {
-       uint8_t *frag_data = (uint8_t *)prs_data_p(current_pdu);
        struct dcerpc_auth auth_info;
        DATA_BLOB blob;
        NTSTATUS status;
@@ -646,7 +613,7 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli,
        }
 
        /* get the auth blob at the end of the packet */
-       blob = data_blob_const(frag_data + pkt->frag_length
+       blob = data_blob_const(pdu->data + pkt->frag_length
                                - DCERPC_AUTH_TRAILER_LENGTH
                                - pkt->auth_length,
                               DCERPC_AUTH_TRAILER_LENGTH
@@ -683,12 +650,12 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli,
                /* Data is encrypted. */
                status = ntlmssp_unseal_packet(
                                        cli->auth->a_u.ntlmssp_state,
-                                       &frag_data[DCERPC_RESPONSE_LENGTH],
+                                       pdu->data + DCERPC_RESPONSE_LENGTH,
                                        pkt->frag_length
                                                - DCERPC_RESPONSE_LENGTH
                                                - DCERPC_AUTH_TRAILER_LENGTH
                                                - pkt->auth_length,
-                                       frag_data,
+                                       pdu->data,
                                        pkt->frag_length - pkt->auth_length,
                                        &auth_info.credentials);
                if (!NT_STATUS_IS_OK(status)) {
@@ -704,12 +671,12 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli,
                /* Data is signed. */
                status = ntlmssp_check_packet(
                                        cli->auth->a_u.ntlmssp_state,
-                                       &frag_data[DCERPC_RESPONSE_LENGTH],
+                                       pdu->data + DCERPC_RESPONSE_LENGTH,
                                        pkt->frag_length
                                                - DCERPC_RESPONSE_LENGTH
                                                - DCERPC_AUTH_TRAILER_LENGTH
                                                - pkt->auth_length,
-                                       frag_data,
+                                       pdu->data,
                                        pkt->frag_length - pkt->auth_length,
                                        &auth_info.credentials);
                if (!NT_STATUS_IS_OK(status)) {
@@ -743,10 +710,9 @@ static NTSTATUS cli_pipe_verify_ntlmssp(struct rpc_pipe_client *cli,
 
 static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli,
                                         struct ncacn_packet *pkt,
-                                        prs_struct *current_pdu,
+                                        DATA_BLOB *pdu,
                                         uint8 *p_ss_padding_len)
 {
-       uint8_t *frag_data = (uint8_t *)prs_data_p(current_pdu);
        struct dcerpc_auth auth_info;
        DATA_BLOB blob;
        NTSTATUS status;
@@ -776,7 +742,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli,
        }
 
        /* get the auth blob at the end of the packet */
-       blob = data_blob_const(frag_data + pkt->frag_length
+       blob = data_blob_const(pdu->data + pkt->frag_length
                                - DCERPC_AUTH_TRAILER_LENGTH
                                - pkt->auth_length,
                               DCERPC_AUTH_TRAILER_LENGTH
@@ -818,7 +784,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli,
                                        cli->auth->a_u.schannel_auth,
                                        talloc_tos(),
                                        true,
-                                       &frag_data[DCERPC_RESPONSE_LENGTH],
+                                       pdu->data + DCERPC_RESPONSE_LENGTH,
                                        pkt->frag_length
                                                - DCERPC_RESPONSE_LENGTH
                                                - DCERPC_AUTH_TRAILER_LENGTH
@@ -830,7 +796,7 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli,
                                        cli->auth->a_u.schannel_auth,
                                        talloc_tos(),
                                        false,
-                                       &frag_data[DCERPC_RESPONSE_LENGTH],
+                                       pdu->data + DCERPC_RESPONSE_LENGTH,
                                        pkt->frag_length
                                                - DCERPC_RESPONSE_LENGTH
                                                - DCERPC_AUTH_TRAILER_LENGTH
@@ -865,9 +831,9 @@ static NTSTATUS cli_pipe_verify_schannel(struct rpc_pipe_client *cli,
  ****************************************************************************/
 
 static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli,
-                               struct ncacn_packet *pkt,
-                               prs_struct *current_pdu,
-                               uint8 *p_ss_padding_len)
+                                               struct ncacn_packet *pkt,
+                                               DATA_BLOB *pdu,
+                                               uint8 *p_ss_padding_len)
 {
        NTSTATUS ret = NT_STATUS_OK;
 
@@ -906,16 +872,16 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli,
 
        case PIPE_AUTH_TYPE_NTLMSSP:
        case PIPE_AUTH_TYPE_SPNEGO_NTLMSSP:
-               ret = cli_pipe_verify_ntlmssp(cli, pkt, current_pdu,
-                                                  p_ss_padding_len);
+               ret = cli_pipe_verify_ntlmssp(cli, pkt, pdu,
+                                               p_ss_padding_len);
                if (!NT_STATUS_IS_OK(ret)) {
                        return ret;
                }
                break;
 
        case PIPE_AUTH_TYPE_SCHANNEL:
-               ret = cli_pipe_verify_schannel(cli, pkt, current_pdu,
-                                                   p_ss_padding_len);
+               ret = cli_pipe_verify_schannel(cli, pkt, pdu,
+                                               p_ss_padding_len);
                if (!NT_STATUS_IS_OK(ret)) {
                        return ret;
                }
@@ -940,37 +906,22 @@ static NTSTATUS cli_pipe_validate_rpc_response(struct rpc_pipe_client *cli,
 
 static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli,
                        struct ncacn_packet *pkt,
-                       prs_struct *current_pdu,
+                       DATA_BLOB *pdu,
                        uint8 expected_pkt_type,
-                       char **ppdata,
-                       uint32 *pdata_len,
+                       DATA_BLOB *rdata,
                        prs_struct *return_data)
 {
        NTSTATUS ret = NT_STATUS_OK;
-       uint32 current_pdu_len = prs_data_size(current_pdu);
-       DATA_BLOB blob = data_blob_const(prs_data_p(current_pdu),
-                                        prs_data_size(current_pdu));
        uint8 ss_padding_len = 0;
 
-       ret = dcerpc_pull_ncacn_packet(cli, &blob, pkt);
+       ret = dcerpc_pull_ncacn_packet(cli, pdu, pkt);
        if (!NT_STATUS_IS_OK(ret)) {
                return ret;
        }
 
-       /* FIXME: although we already unmarshalled the whole packet,
-        *        set the offset of the pdu to right after the header
-        *        until the rest of the code downstream is changed
-        *        to always use the already decoded packet and not try
-        *        to unmarshall bits of the packet.
-        */
-       if (!prs_set_offset(current_pdu,
-                           prs_offset(current_pdu) + RPC_HEADER_LEN)) {
-               return NT_STATUS_BUFFER_TOO_SMALL;
-       }
-
-       if (current_pdu_len != pkt->frag_length) {
+       if (pdu->length != pkt->frag_length) {
                DEBUG(5, ("Incorrect pdu length %u, expected %u\n",
-                         (unsigned int)current_pdu_len,
+                         (unsigned int)pdu->length,
                          (unsigned int)pkt->frag_length));
                return NT_STATUS_INVALID_PARAMETER;
        }
@@ -979,8 +930,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli,
         * Point the return values at the real data including the RPC
         * header. Just in case the caller wants it.
         */
-       *ppdata = prs_data_p(current_pdu);
-       *pdata_len = current_pdu_len;
+       *rdata = *pdu;
 
        /* Ensure we have the correct type. */
        switch (pkt->ptype) {
@@ -994,36 +944,38 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli,
        case DCERPC_PKT_RESPONSE:
 
                /* Here's where we deal with incoming sign/seal. */
-               ret = cli_pipe_validate_rpc_response(cli, pkt,
-                               current_pdu, &ss_padding_len);
+               ret = cli_pipe_validate_rpc_response(cli, pkt, pdu,
+                                                    &ss_padding_len);
                if (!NT_STATUS_IS_OK(ret)) {
                        return ret;
                }
 
                /* Point the return values at the NDR data.
                 * Remember to remove any ss padding. */
-               *ppdata = prs_data_p(current_pdu) + DCERPC_RESPONSE_LENGTH;
+               rdata->data = pdu->data + DCERPC_RESPONSE_LENGTH;
 
-               if (current_pdu_len < DCERPC_RESPONSE_LENGTH + ss_padding_len) {
+               if (pdu->length < DCERPC_RESPONSE_LENGTH + ss_padding_len) {
                        return NT_STATUS_BUFFER_TOO_SMALL;
                }
 
-               *pdata_len = current_pdu_len - DCERPC_RESPONSE_LENGTH - ss_padding_len;
+               rdata->length = pdu->length
+                                       - DCERPC_RESPONSE_LENGTH
+                                       - ss_padding_len;
 
                /* Remember to remove the auth footer. */
                if (pkt->auth_length) {
                        /* We've already done integer wrap tests on auth_len in
                                cli_pipe_validate_rpc_response(). */
-                       if (*pdata_len < DCERPC_AUTH_TRAILER_LENGTH
-                                               + pkt->auth_length) {
+                       if (rdata->length < DCERPC_AUTH_TRAILER_LENGTH
+                                                       + pkt->auth_length) {
                                return NT_STATUS_BUFFER_TOO_SMALL;
                        }
-                       *pdata_len -= (DCERPC_AUTH_TRAILER_LENGTH
-                                               + pkt->auth_length);
+                       rdata->length -= (DCERPC_AUTH_TRAILER_LENGTH
+                                                       + pkt->auth_length);
                }
 
-               DEBUG(10, ("Got pdu len %u, data_len %u, ss_len %u\n",
-                          current_pdu_len, *pdata_len, ss_padding_len));
+               DEBUG(10, ("Got pdu len %lu, data_len %lu, ss_len %u\n",
+                          pdu->length, rdata->length, ss_padding_len));
 
                /*
                 * If this is the first reply, and the allocation hint is
@@ -1097,43 +1049,6 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli,
        return NT_STATUS_OK;
 }
 
-/****************************************************************************
- Ensure we eat the just processed pdu from the current_pdu prs_struct.
- Normally the frag_len and buffer size will match, but on the first trans
- reply there is a theoretical chance that buffer size > frag_len, so we must
- deal with that.
- ****************************************************************************/
-
-static NTSTATUS cli_pipe_reset_current_pdu(struct rpc_pipe_client *cli,
-                                          struct ncacn_packet *pkt,
-                                          prs_struct *current_pdu)
-{
-       uint32 current_pdu_len = prs_data_size(current_pdu);
-
-       if (current_pdu_len < pkt->frag_length) {
-               return NT_STATUS_BUFFER_TOO_SMALL;
-       }
-
-       /* Common case. */
-       if (current_pdu_len == (uint32)pkt->frag_length) {
-               prs_mem_free(current_pdu);
-               prs_init_empty(current_pdu, prs_get_mem_context(current_pdu), UNMARSHALL);
-               /* Make current_pdu dynamic with no memory. */
-               prs_give_memory(current_pdu, 0, 0, True);
-               return NT_STATUS_OK;
-       }
-
-       /*
-        * Oh no ! More data in buffer than we processed in current pdu.
-        * This shouldn't happen, we only read exactly pkt->frag_length.
-        * Something is wrong here, throw an error.
-        */
-
-       DEBUG(0, ("Data buffer size (%u) and pkt->frag_length (%u) differ\n!",
-                 (unsigned)current_pdu_len, (unsigned)pkt->frag_length));
-       return NT_STATUS_INVALID_BUFFER_SIZE;
-}
-
 /****************************************************************************
  Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
 ****************************************************************************/
@@ -1324,7 +1239,7 @@ struct rpc_api_pipe_state {
        struct rpc_pipe_client *cli;
        uint8_t expected_pkt_type;
 
-       prs_struct incoming_frag;
+       DATA_BLOB incoming_frag;
        struct ncacn_packet *pkt;
 
        prs_struct incoming_pdu;        /* Incoming reply */
@@ -1353,8 +1268,7 @@ static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
        state->cli = cli;
        state->expected_pkt_type = expected_pkt_type;
        state->incoming_pdu_offset = 0;
-
-       prs_init_empty(&state->incoming_frag, state, UNMARSHALL);
+       state->incoming_frag = data_blob_null;
 
        prs_init_empty(&state->incoming_pdu, state, UNMARSHALL);
        /* Make incoming_pdu dynamic with no memory. */
@@ -1417,11 +1331,14 @@ static void rpc_api_pipe_trans_done(struct tevent_req *subreq)
        }
 
        /*
-        * This is equivalent to a talloc_steal - gives rdata to
-        * the prs_struct state->incoming_frag.
+        * Move data on state->incoming_frag.
         */
-       prs_give_memory(&state->incoming_frag, (char *)rdata, rdata_len, true);
-       rdata = NULL;
+       state->incoming_frag.data = talloc_move(state, &rdata);
+       state->incoming_frag.length = rdata_len;
+       if (!state->incoming_frag.data) {
+               tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
+               return;
+       }
 
        /* Ensure we have enough data for a pdu. */
        subreq = get_complete_frag_send(state, state->ev, state->cli,
@@ -1439,8 +1356,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
        struct rpc_api_pipe_state *state = tevent_req_data(
                req, struct rpc_api_pipe_state);
        NTSTATUS status;
-       char *rdata = NULL;
-       uint32_t rdata_len = 0;
+       DATA_BLOB rdata = data_blob_null;
 
        status = get_complete_frag_recv(subreq);
        TALLOC_FREE(subreq);
@@ -1457,13 +1373,14 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
                return;
        }
 
-       status = cli_pipe_validate_current_pdu(
-               state->cli, state->pkt, &state->incoming_frag,
-               state->expected_pkt_type, &rdata, &rdata_len,
-               &state->incoming_pdu);
+       status = cli_pipe_validate_current_pdu(state->cli, state->pkt,
+                                               &state->incoming_frag,
+                                               state->expected_pkt_type,
+                                               &rdata,
+                                               &state->incoming_pdu);
 
        DEBUG(10,("rpc_api_pipe: got frag len of %u at offset %u: %s\n",
-                 (unsigned)prs_data_size(&state->incoming_frag),
+                 (unsigned)state->incoming_frag.length,
                  (unsigned)state->incoming_pdu_offset,
                  nt_errstr(status)));
 
@@ -1473,7 +1390,7 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
        }
 
        if ((state->pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)
-           && (state->pkt->drep[0] == 0)) {
+           && (state->pkt->drep[0] != DCERPC_DREP_LE)) {
                /*
                 * Set the data type correctly for big-endian data on the
                 * first packet.
@@ -1486,32 +1403,30 @@ static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
        /*
         * Check endianness on subsequent packets.
         */
-       if (state->incoming_frag.bigendian_data
-           != state->incoming_pdu.bigendian_data) {
+       if (state->incoming_pdu.bigendian_data &&
+           (state->pkt->drep[0] == DCERPC_DREP_LE)) {
                DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to "
                         "%s\n",
                         state->incoming_pdu.bigendian_data?"big":"little",
-                        state->incoming_frag.bigendian_data?"big":"little"));
+                        (state->pkt->drep[0] != DCERPC_DREP_LE)?"big":"little"));
                tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
                return;
        }
 
        /* Now copy the data portion out of the pdu into rbuf. */
-       if (!prs_force_grow(&state->incoming_pdu, rdata_len)) {
+       if (!prs_force_grow(&state->incoming_pdu, rdata.length)) {
                tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
 
        memcpy(prs_data_p(&state->incoming_pdu) + state->incoming_pdu_offset,
-              rdata, (size_t)rdata_len);
-       state->incoming_pdu_offset += rdata_len;
+              rdata.data, rdata.length);
+       state->incoming_pdu_offset += rdata.length;
 
-       status = cli_pipe_reset_current_pdu(state->cli, state->pkt,
-                                           &state->incoming_frag);
-       if (!NT_STATUS_IS_OK(status)) {
-               tevent_req_nterror(req, status);
-               return;
-       }
+       /* reset state->incoming_frag, there is no need to free it,
+        * it will be reallocated to the right size the next time
+        * it is used */
+       state->incoming_frag.length = 0;
 
        if (state->pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
                DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n",