root/source4/librpc/rpc/dcerpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dcerpc_init
  2. dcerpc_connection_destructor
  3. dcerpc_connection_init
  4. dcerpc_pipe_init
  5. next_call_id
  6. dcerpc_set_frag_length
  7. dcerpc_get_frag_length
  8. dcerpc_set_auth_length
  9. ndr_pull_init_flags
  10. ncacn_pull
  11. ncacn_pull_request_auth
  12. ncacn_push_request_sign
  13. init_ncacn_hdr
  14. dcerpc_map_reason
  15. dcerpc_composite_fail
  16. dcerpc_req_dequeue
  17. dcerpc_connection_dead
  18. dcerpc_recv_data
  19. dcerpc_bind_recv_handler
  20. dcerpc_timeout_handler
  21. dcerpc_bind_send
  22. dcerpc_bind_recv
  23. dcerpc_auth3
  24. dcerpc_request_recv_data
  25. dcerpc_request_send
  26. dcerpc_ship_next_request
  27. dcerpc_event_context
  28. dcerpc_request_recv
  29. dcerpc_request
  30. dcerpc_ndr_validate_in
  31. dcerpc_ndr_validate_out
  32. dcerpc_ndr_request_send
  33. dcerpc_ndr_request_recv
  34. dcerpc_ndr_request
  35. dcerpc_server_name
  36. dcerpc_auth_level
  37. dcerpc_alter_recv_handler
  38. dcerpc_alter_context_send
  39. dcerpc_alter_context_recv
  40. dcerpc_alter_context

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    raw dcerpc operations
   4 
   5    Copyright (C) Tim Potter 2003
   6    Copyright (C) Andrew Tridgell 2003-2005
   7    Copyright (C) Jelmer Vernooij 2004-2005
   8    
   9    This program is free software; you can redistribute it and/or modify
  10    it under the terms of the GNU General Public License as published by
  11    the Free Software Foundation; either version 3 of the License, or
  12    (at your option) any later version.
  13    
  14    This program is distributed in the hope that it will be useful,
  15    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17    GNU General Public License for more details.
  18    
  19    You should have received a copy of the GNU General Public License
  20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22 
  23 #include "includes.h"
  24 #include "../lib/util/dlinklist.h"
  25 #include "lib/events/events.h"
  26 #include "librpc/rpc/dcerpc.h"
  27 #include "librpc/rpc/dcerpc_proto.h"
  28 #include "librpc/gen_ndr/ndr_misc.h"
  29 #include "librpc/gen_ndr/ndr_dcerpc.h"
  30 #include "libcli/composite/composite.h"
  31 #include "auth/gensec/gensec.h"
  32 #include "param/param.h"
  33 
  34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  35 {
  36         return gensec_init(lp_ctx);
  37 }
  38 
  39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
  40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
  41 
  42 /* destroy a dcerpc connection */
  43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
  44 {
  45         if (conn->dead) {
  46                 conn->free_skipped = true;
  47                 return -1;
  48         }
  49         dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
  50         return 0;
  51 }
  52 
  53 
  54 /* initialise a dcerpc connection. 
  55    the event context is optional
  56 */
  57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
  58                                                  struct tevent_context *ev,
  59                                                  struct smb_iconv_convenience *ic)
  60 {
  61         struct dcerpc_connection *c;
  62 
  63         c = talloc_zero(mem_ctx, struct dcerpc_connection);
  64         if (!c) {
  65                 return NULL;
  66         }
  67 
  68         c->iconv_convenience = talloc_reference(c, ic);
  69 
  70         c->event_ctx = talloc_reference(c, ev);
  71 
  72         if (c->event_ctx == NULL) {
  73                 talloc_free(c);
  74                 return NULL;
  75         }
  76 
  77         c->call_id = 1;
  78         c->security_state.auth_info = NULL;
  79         c->security_state.session_key = dcerpc_generic_session_key;
  80         c->security_state.generic_state = NULL;
  81         c->binding_string = NULL;
  82         c->flags = 0;
  83         c->srv_max_xmit_frag = 0;
  84         c->srv_max_recv_frag = 0;
  85         c->pending = NULL;
  86 
  87         talloc_set_destructor(c, dcerpc_connection_destructor);
  88 
  89         return c;
  90 }
  91 
  92 /* initialise a dcerpc pipe. */
  93 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     /* [<][>][^][v][top][bottom][index][help] */
  94                                      struct smb_iconv_convenience *ic)
  95 {
  96         struct dcerpc_pipe *p;
  97 
  98         p = talloc(mem_ctx, struct dcerpc_pipe);
  99         if (!p) {
 100                 return NULL;
 101         }
 102 
 103         p->conn = dcerpc_connection_init(p, ev, ic);
 104         if (p->conn == NULL) {
 105                 talloc_free(p);
 106                 return NULL;
 107         }
 108 
 109         p->last_fault_code = 0;
 110         p->context_id = 0;
 111         p->request_timeout = DCERPC_REQUEST_TIMEOUT;
 112         p->binding = NULL;
 113 
 114         ZERO_STRUCT(p->syntax);
 115         ZERO_STRUCT(p->transfer_syntax);
 116 
 117         return p;
 118 }
 119 
 120 
 121 /* 
 122    choose the next call id to use
 123 */
 124 static uint32_t next_call_id(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 125 {
 126         c->call_id++;
 127         if (c->call_id == 0) {
 128                 c->call_id++;
 129         }
 130         return c->call_id;
 131 }
 132 
 133 /* we need to be able to get/set the fragment length without doing a full
 134    decode */
 135 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
     /* [<][>][^][v][top][bottom][index][help] */
 136 {
 137         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
 138                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
 139         } else {
 140                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
 141         }
 142 }
 143 
 144 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
     /* [<][>][^][v][top][bottom][index][help] */
 145 {
 146         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
 147                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
 148         } else {
 149                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
 150         }
 151 }
 152 
 153 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
     /* [<][>][^][v][top][bottom][index][help] */
 154 {
 155         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
 156                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
 157         } else {
 158                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
 159         }
 160 }
 161 
 162 
 163 /**
 164   setup for a ndr pull, also setting up any flags from the binding string
 165 */
 166 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 167                                             DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
 168 {
 169         struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
 170 
 171         if (ndr == NULL) return ndr;
 172 
 173         if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
 174                 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
 175         }
 176 
 177         if (c->flags & DCERPC_NDR_REF_ALLOC) {
 178                 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
 179         }
 180 
 181         return ndr;
 182 }
 183 
 184 /* 
 185    parse a data blob into a ncacn_packet structure. This handles both
 186    input and output packets
 187 */
 188 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 189                             struct ncacn_packet *pkt)
 190 {
 191         struct ndr_pull *ndr;
 192         enum ndr_err_code ndr_err;
 193 
 194         ndr = ndr_pull_init_flags(c, blob, mem_ctx);
 195         if (!ndr) {
 196                 return NT_STATUS_NO_MEMORY;
 197         }
 198 
 199         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
 200                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
 201         }
 202 
 203         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
 204         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 205                 return ndr_map_error2ntstatus(ndr_err);
 206         }
 207 
 208         return NT_STATUS_OK;
 209 }
 210 
 211 /* 
 212    parse the authentication information on a dcerpc response packet
 213 */
 214 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 215                                         DATA_BLOB *raw_packet,
 216                                         struct ncacn_packet *pkt)
 217 {
 218         struct ndr_pull *ndr;
 219         NTSTATUS status;
 220         struct dcerpc_auth auth;
 221         DATA_BLOB auth_blob;
 222         enum ndr_err_code ndr_err;
 223 
 224         if (!c->security_state.auth_info ||
 225             !c->security_state.generic_state) {
 226                 return NT_STATUS_OK;
 227         }
 228 
 229         switch (c->security_state.auth_info->auth_level) {
 230         case DCERPC_AUTH_LEVEL_PRIVACY:
 231         case DCERPC_AUTH_LEVEL_INTEGRITY:
 232                 break;
 233 
 234         case DCERPC_AUTH_LEVEL_CONNECT:
 235                 if (pkt->auth_length != 0) {
 236                         break;
 237                 }
 238                 return NT_STATUS_OK;
 239         case DCERPC_AUTH_LEVEL_NONE:
 240                 if (pkt->auth_length != 0) {
 241                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
 242                 }
 243                 return NT_STATUS_OK;
 244 
 245         default:
 246                 return NT_STATUS_INVALID_LEVEL;
 247         }
 248 
 249         auth_blob.length = 8 + pkt->auth_length;
 250 
 251         /* check for a valid length */
 252         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
 253                 return NT_STATUS_INFO_LENGTH_MISMATCH;
 254         }
 255 
 256         auth_blob.data = 
 257                 pkt->u.response.stub_and_verifier.data + 
 258                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
 259         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
 260 
 261         /* pull the auth structure */
 262         ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
 263         if (!ndr) {
 264                 return NT_STATUS_NO_MEMORY;
 265         }
 266 
 267         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
 268                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
 269         }
 270 
 271         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
 272         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 273                 return ndr_map_error2ntstatus(ndr_err);
 274         }
 275         status = NT_STATUS_OK;
 276 
 277         /* check signature or unseal the packet */
 278         switch (c->security_state.auth_info->auth_level) {
 279         case DCERPC_AUTH_LEVEL_PRIVACY:
 280                 status = gensec_unseal_packet(c->security_state.generic_state, 
 281                                               mem_ctx, 
 282                                               raw_packet->data + DCERPC_REQUEST_LENGTH,
 283                                               pkt->u.response.stub_and_verifier.length, 
 284                                               raw_packet->data,
 285                                               raw_packet->length - auth.credentials.length,
 286                                               &auth.credentials);
 287                 memcpy(pkt->u.response.stub_and_verifier.data,
 288                        raw_packet->data + DCERPC_REQUEST_LENGTH,
 289                        pkt->u.response.stub_and_verifier.length);
 290                 break;
 291                 
 292         case DCERPC_AUTH_LEVEL_INTEGRITY:
 293                 status = gensec_check_packet(c->security_state.generic_state, 
 294                                              mem_ctx, 
 295                                              pkt->u.response.stub_and_verifier.data, 
 296                                              pkt->u.response.stub_and_verifier.length, 
 297                                              raw_packet->data,
 298                                              raw_packet->length - auth.credentials.length,
 299                                              &auth.credentials);
 300                 break;
 301 
 302         case DCERPC_AUTH_LEVEL_CONNECT:
 303                 /* for now we ignore possible signatures here */
 304                 status = NT_STATUS_OK;
 305                 break;
 306 
 307         default:
 308                 status = NT_STATUS_INVALID_LEVEL;
 309                 break;
 310         }
 311         
 312         /* remove the indicated amount of paddiing */
 313         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
 314                 return NT_STATUS_INFO_LENGTH_MISMATCH;
 315         }
 316         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
 317 
 318         return status;
 319 }
 320 
 321 
 322 /* 
 323    push a dcerpc request packet into a blob, possibly signing it.
 324 */
 325 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 326                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
 327                                          size_t sig_size,
 328                                          struct ncacn_packet *pkt)
 329 {
 330         NTSTATUS status;
 331         struct ndr_push *ndr;
 332         DATA_BLOB creds2;
 333         size_t payload_length;
 334         enum ndr_err_code ndr_err;
 335         size_t hdr_size = DCERPC_REQUEST_LENGTH;
 336 
 337         /* non-signed packets are simpler */
 338         if (sig_size == 0) {
 339                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
 340         }
 341 
 342         switch (c->security_state.auth_info->auth_level) {
 343         case DCERPC_AUTH_LEVEL_PRIVACY:
 344         case DCERPC_AUTH_LEVEL_INTEGRITY:
 345                 break;
 346 
 347         case DCERPC_AUTH_LEVEL_CONNECT:
 348                 /* TODO: let the gensec mech decide if it wants to generate a signature */
 349                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
 350 
 351         case DCERPC_AUTH_LEVEL_NONE:
 352                 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
 353 
 354         default:
 355                 return NT_STATUS_INVALID_LEVEL;
 356         }
 357 
 358         ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
 359         if (!ndr) {
 360                 return NT_STATUS_NO_MEMORY;
 361         }
 362 
 363         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
 364                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
 365         }
 366 
 367         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
 368                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
 369                 hdr_size += 16;
 370         }
 371 
 372         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
 373         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 374                 return ndr_map_error2ntstatus(ndr_err);
 375         }
 376         status = NT_STATUS_OK;
 377 
 378         /* pad to 16 byte multiple in the payload portion of the
 379            packet. This matches what w2k3 does */
 380         c->security_state.auth_info->auth_pad_length = 
 381                 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
 382         ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
 383         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 384                 return ndr_map_error2ntstatus(ndr_err);
 385         }
 386         status = NT_STATUS_OK;
 387 
 388         payload_length = pkt->u.request.stub_and_verifier.length + 
 389                 c->security_state.auth_info->auth_pad_length;
 390 
 391         /* we start without signature, it will appended later */
 392         c->security_state.auth_info->credentials = data_blob(NULL,0);
 393 
 394         /* add the auth verifier */
 395         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
 396         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 397                 return ndr_map_error2ntstatus(ndr_err);
 398         }
 399         status = NT_STATUS_OK;
 400 
 401         /* extract the whole packet as a blob */
 402         *blob = ndr_push_blob(ndr);
 403 
 404         /*
 405          * Setup the frag and auth length in the packet buffer.
 406          * This is needed if the GENSEC mech does AEAD signing
 407          * of the packet headers. The signature itself will be
 408          * appended later.
 409          */
 410         dcerpc_set_frag_length(blob, blob->length + sig_size);
 411         dcerpc_set_auth_length(blob, sig_size);
 412 
 413         /* sign or seal the packet */
 414         switch (c->security_state.auth_info->auth_level) {
 415         case DCERPC_AUTH_LEVEL_PRIVACY:
 416                 status = gensec_seal_packet(c->security_state.generic_state, 
 417                                             mem_ctx, 
 418                                             blob->data + hdr_size,
 419                                             payload_length,
 420                                             blob->data,
 421                                             blob->length,
 422                                             &creds2);
 423                 if (!NT_STATUS_IS_OK(status)) {
 424                         return status;
 425                 }
 426                 break;
 427 
 428         case DCERPC_AUTH_LEVEL_INTEGRITY:
 429                 status = gensec_sign_packet(c->security_state.generic_state, 
 430                                             mem_ctx, 
 431                                             blob->data + hdr_size,
 432                                             payload_length, 
 433                                             blob->data,
 434                                             blob->length,
 435                                             &creds2);
 436                 if (!NT_STATUS_IS_OK(status)) {
 437                         return status;
 438                 }
 439                 break;
 440 
 441         default:
 442                 status = NT_STATUS_INVALID_LEVEL;
 443                 break;
 444         }
 445 
 446         if (creds2.length != sig_size) {
 447                 DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
 448                         creds2.length, (uint32_t)sig_size,
 449                         c->security_state.auth_info->auth_pad_length,
 450                         pkt->u.request.stub_and_verifier.length));
 451                 return NT_STATUS_INTERNAL_ERROR;
 452         }
 453 
 454         if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
 455                 return NT_STATUS_NO_MEMORY;
 456         }
 457 
 458         return NT_STATUS_OK;
 459 }
 460 
 461 
 462 /* 
 463    fill in the fixed values in a dcerpc header 
 464 */
 465 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
     /* [<][>][^][v][top][bottom][index][help] */
 466 {
 467         pkt->rpc_vers = 5;
 468         pkt->rpc_vers_minor = 0;
 469         if (c->flags & DCERPC_PUSH_BIGENDIAN) {
 470                 pkt->drep[0] = 0;
 471         } else {
 472                 pkt->drep[0] = DCERPC_DREP_LE;
 473         }
 474         pkt->drep[1] = 0;
 475         pkt->drep[2] = 0;
 476         pkt->drep[3] = 0;
 477 }
 478 
 479 /*
 480   map a bind nak reason to a NTSTATUS
 481 */
 482 static NTSTATUS dcerpc_map_reason(uint16_t reason)
     /* [<][>][^][v][top][bottom][index][help] */
 483 {
 484         switch (reason) {
 485         case DCERPC_BIND_REASON_ASYNTAX:
 486                 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
 487         case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
 488                 return NT_STATUS_INVALID_PARAMETER;
 489         }
 490         return NT_STATUS_UNSUCCESSFUL;
 491 }
 492 
 493 /*
 494   a bind or alter context has failed
 495 */
 496 static void dcerpc_composite_fail(struct rpc_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 497 {
 498         struct composite_context *c = talloc_get_type(req->async.private_data, 
 499                                                       struct composite_context);
 500         composite_error(c, req->status);
 501 }
 502 
 503 /*
 504   remove requests from the pending or queued queues
 505  */
 506 static int dcerpc_req_dequeue(struct rpc_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 507 {
 508         switch (req->state) {
 509         case RPC_REQUEST_QUEUED:
 510                 DLIST_REMOVE(req->p->conn->request_queue, req);
 511                 break;
 512         case RPC_REQUEST_PENDING:
 513                 DLIST_REMOVE(req->p->conn->pending, req);
 514                 break;
 515         case RPC_REQUEST_DONE:
 516                 break;
 517         }
 518         return 0;
 519 }
 520 
 521 
 522 /*
 523   mark the dcerpc connection dead. All outstanding requests get an error
 524 */
 525 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 526 {
 527         if (conn->dead) return;
 528 
 529         conn->dead = true;
 530 
 531         if (conn->transport.shutdown_pipe) {
 532                 conn->transport.shutdown_pipe(conn, status);
 533         }
 534 
 535         /* all pending requests get the error */
 536         while (conn->pending) {
 537                 struct rpc_request *req = conn->pending;
 538                 dcerpc_req_dequeue(req);
 539                 req->state = RPC_REQUEST_DONE;
 540                 req->status = status;
 541                 if (req->async.callback) {
 542                         req->async.callback(req);
 543                 }
 544         }       
 545 
 546         talloc_set_destructor(conn, NULL);
 547         if (conn->free_skipped) {
 548                 talloc_free(conn);
 549         }
 550 }
 551 
 552 /*
 553   forward declarations of the recv_data handlers for the types of
 554   packets we need to handle
 555 */
 556 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
 557                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
 558 
 559 /*
 560   receive a dcerpc reply from the transport. Here we work out what
 561   type of reply it is (normal request, bind or alter context) and
 562   dispatch to the appropriate handler
 563 */
 564 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 565 {
 566         struct ncacn_packet pkt;
 567 
 568         if (NT_STATUS_IS_OK(status) && blob->length == 0) {
 569                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 570         }
 571 
 572         /* the transport may be telling us of a severe error, such as
 573            a dropped socket */
 574         if (!NT_STATUS_IS_OK(status)) {
 575                 data_blob_free(blob);
 576                 dcerpc_connection_dead(conn, status);
 577                 return;
 578         }
 579 
 580         /* parse the basic packet to work out what type of response this is */
 581         status = ncacn_pull(conn, blob, blob->data, &pkt);
 582         if (!NT_STATUS_IS_OK(status)) {
 583                 data_blob_free(blob);
 584                 dcerpc_connection_dead(conn, status);
 585         }
 586 
 587         dcerpc_request_recv_data(conn, blob, &pkt);
 588 }
 589 
 590 
 591 /*
 592   Receive a bind reply from the transport
 593 */
 594 static void dcerpc_bind_recv_handler(struct rpc_request *req, 
     /* [<][>][^][v][top][bottom][index][help] */
 595                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
 596 {
 597         struct composite_context *c;
 598         struct dcerpc_connection *conn;
 599 
 600         c = talloc_get_type(req->async.private_data, struct composite_context);
 601 
 602         if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
 603                 DEBUG(2,("dcerpc: bind_nak reason %d\n",
 604                          pkt->u.bind_nak.reject_reason));
 605                 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
 606                                                      reject_reason));
 607                 return;
 608         }
 609 
 610         if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
 611             (pkt->u.bind_ack.num_results == 0) ||
 612             (pkt->u.bind_ack.ctx_list[0].result != 0)) {
 613                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
 614                 return;
 615         }
 616 
 617         conn = req->p->conn;
 618 
 619         conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
 620         conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
 621 
 622         if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
 623             (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
 624                 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
 625         }
 626 
 627         if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
 628             (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
 629                 conn->flags |= DCERPC_HEADER_SIGNING;
 630         }
 631 
 632         /* the bind_ack might contain a reply set of credentials */
 633         if (conn->security_state.auth_info &&
 634             pkt->u.bind_ack.auth_info.length) {
 635                 enum ndr_err_code ndr_err;
 636                 ndr_err = ndr_pull_struct_blob(
 637                         &pkt->u.bind_ack.auth_info, conn,
 638                         NULL,
 639                         conn->security_state.auth_info,
 640                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
 641                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 642                         c->status = ndr_map_error2ntstatus(ndr_err);
 643                         if (!composite_is_ok(c)) return;
 644                 }
 645         }
 646 
 647         req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
 648 
 649         composite_done(c);
 650 }
 651 
 652 /*
 653   handle timeouts of individual dcerpc requests
 654 */
 655 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
     /* [<][>][^][v][top][bottom][index][help] */
 656                                    struct timeval t, void *private_data)
 657 {
 658         struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
 659 
 660         if (req->ignore_timeout) {
 661                 dcerpc_req_dequeue(req);
 662                 req->state = RPC_REQUEST_DONE;
 663                 req->status = NT_STATUS_IO_TIMEOUT;
 664                 if (req->async.callback) {
 665                         req->async.callback(req);
 666                 }
 667                 return;
 668         }
 669 
 670         dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
 671 }
 672 
 673 /*
 674   send a async dcerpc bind request
 675 */
 676 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
     /* [<][>][^][v][top][bottom][index][help] */
 677                                            TALLOC_CTX *mem_ctx,
 678                                            const struct ndr_syntax_id *syntax,
 679                                            const struct ndr_syntax_id *transfer_syntax)
 680 {
 681         struct composite_context *c;
 682         struct ncacn_packet pkt;
 683         DATA_BLOB blob;
 684         struct rpc_request *req;
 685 
 686         c = composite_create(mem_ctx,p->conn->event_ctx);
 687         if (c == NULL) return NULL;
 688 
 689         c->private_data = p;
 690 
 691         p->syntax = *syntax;
 692         p->transfer_syntax = *transfer_syntax;
 693 
 694         init_ncacn_hdr(p->conn, &pkt);
 695 
 696         pkt.ptype = DCERPC_PKT_BIND;
 697         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 698         pkt.call_id = p->conn->call_id;
 699         pkt.auth_length = 0;
 700 
 701         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
 702                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
 703         }
 704 
 705         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
 706                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
 707         }
 708 
 709         pkt.u.bind.max_xmit_frag = 5840;
 710         pkt.u.bind.max_recv_frag = 5840;
 711         pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
 712         pkt.u.bind.num_contexts = 1;
 713         pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
 714         if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
 715         pkt.u.bind.ctx_list[0].context_id = p->context_id;
 716         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
 717         pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
 718         pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
 719         pkt.u.bind.auth_info = data_blob(NULL, 0);
 720 
 721         /* construct the NDR form of the packet */
 722         c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
 723                                     p->conn->security_state.auth_info);
 724         if (!composite_is_ok(c)) return c;
 725 
 726         p->conn->transport.recv_data = dcerpc_recv_data;
 727 
 728         /*
 729          * we allocate a dcerpc_request so we can be in the same
 730          * request queue as normal requests
 731          */
 732         req = talloc_zero(c, struct rpc_request);
 733         if (composite_nomem(req, c)) return c;
 734 
 735         req->state = RPC_REQUEST_PENDING;
 736         req->call_id = pkt.call_id;
 737         req->async.private_data = c;
 738         req->async.callback = dcerpc_composite_fail;
 739         req->p = p;
 740         req->recv_handler = dcerpc_bind_recv_handler;
 741         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
 742         talloc_set_destructor(req, dcerpc_req_dequeue);
 743 
 744         c->status = p->conn->transport.send_request(p->conn, &blob,
 745                                                     true);
 746         if (!composite_is_ok(c)) return c;
 747 
 748         event_add_timed(c->event_ctx, req,
 749                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
 750                         dcerpc_timeout_handler, req);
 751 
 752         return c;
 753 }
 754 
 755 /*
 756   recv side of async dcerpc bind request
 757 */
 758 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 759 {
 760         NTSTATUS result = composite_wait(ctx);
 761         talloc_free(ctx);
 762         return result;
 763 }
 764 
 765 /* 
 766    perform a continued bind (and auth3)
 767 */
 768 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
     /* [<][>][^][v][top][bottom][index][help] */
 769                       TALLOC_CTX *mem_ctx)
 770 {
 771         struct ncacn_packet pkt;
 772         NTSTATUS status;
 773         DATA_BLOB blob;
 774 
 775         init_ncacn_hdr(p->conn, &pkt);
 776 
 777         pkt.ptype = DCERPC_PKT_AUTH3;
 778         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 779         pkt.call_id = next_call_id(p->conn);
 780         pkt.auth_length = 0;
 781         pkt.u.auth3._pad = 0;
 782         pkt.u.auth3.auth_info = data_blob(NULL, 0);
 783 
 784         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
 785                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
 786         }
 787 
 788         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
 789                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
 790         }
 791 
 792         /* construct the NDR form of the packet */
 793         status = ncacn_push_auth(&blob, mem_ctx,
 794                                  p->conn->iconv_convenience,
 795                                  &pkt,
 796                                  p->conn->security_state.auth_info);
 797         if (!NT_STATUS_IS_OK(status)) {
 798                 return status;
 799         }
 800 
 801         /* send it on its way */
 802         status = p->conn->transport.send_request(p->conn, &blob, false);
 803         if (!NT_STATUS_IS_OK(status)) {
 804                 return status;
 805         }
 806 
 807         return NT_STATUS_OK;    
 808 }
 809 
 810 
 811 /*
 812   process a fragment received from the transport layer during a
 813   request
 814 
 815   This function frees the data 
 816 */
 817 static void dcerpc_request_recv_data(struct dcerpc_connection *c, 
     /* [<][>][^][v][top][bottom][index][help] */
 818                                      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
 819 {
 820         struct rpc_request *req;
 821         uint_t length;
 822         NTSTATUS status = NT_STATUS_OK;
 823 
 824         /*
 825           if this is an authenticated connection then parse and check
 826           the auth info. We have to do this before finding the
 827           matching packet, as the request structure might have been
 828           removed due to a timeout, but if it has been we still need
 829           to run the auth routines so that we don't get the sign/seal
 830           info out of step with the server
 831         */
 832         if (c->security_state.auth_info && c->security_state.generic_state &&
 833             pkt->ptype == DCERPC_PKT_RESPONSE) {
 834                 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
 835         }
 836 
 837         /* find the matching request */
 838         for (req=c->pending;req;req=req->next) {
 839                 if (pkt->call_id == req->call_id) break;
 840         }
 841 
 842 #if 0
 843         /* useful for testing certain vendors RPC servers */
 844         if (req == NULL && c->pending && pkt->call_id == 0) {
 845                 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
 846                 req = c->pending;
 847         }
 848 #endif
 849 
 850         if (req == NULL) {
 851                 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
 852                 data_blob_free(raw_packet);
 853                 return;
 854         }
 855 
 856         talloc_steal(req, raw_packet->data);
 857 
 858         if (req->recv_handler != NULL) {
 859                 dcerpc_req_dequeue(req);
 860                 req->state = RPC_REQUEST_DONE;
 861                 req->recv_handler(req, raw_packet, pkt);
 862                 return;
 863         }
 864 
 865         if (pkt->ptype == DCERPC_PKT_FAULT) {
 866                 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
 867                 req->fault_code = pkt->u.fault.status;
 868                 req->status = NT_STATUS_NET_WRITE_FAULT;
 869                 goto req_done;
 870         }
 871 
 872         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
 873                 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
 874                          (int)pkt->ptype)); 
 875                 req->fault_code = DCERPC_FAULT_OTHER;
 876                 req->status = NT_STATUS_NET_WRITE_FAULT;
 877                 goto req_done;
 878         }
 879 
 880         /* now check the status from the auth routines, and if it failed then fail
 881            this request accordingly */
 882         if (!NT_STATUS_IS_OK(status)) {
 883                 req->status = status;
 884                 goto req_done;
 885         }
 886 
 887         length = pkt->u.response.stub_and_verifier.length;
 888 
 889         if (length > 0) {
 890                 req->payload.data = talloc_realloc(req, 
 891                                                    req->payload.data, 
 892                                                    uint8_t,
 893                                                    req->payload.length + length);
 894                 if (!req->payload.data) {
 895                         req->status = NT_STATUS_NO_MEMORY;
 896                         goto req_done;
 897                 }
 898                 memcpy(req->payload.data+req->payload.length, 
 899                        pkt->u.response.stub_and_verifier.data, length);
 900                 req->payload.length += length;
 901         }
 902 
 903         if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
 904                 c->transport.send_read(c);
 905                 return;
 906         }
 907 
 908         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
 909                 req->flags |= DCERPC_PULL_BIGENDIAN;
 910         } else {
 911                 req->flags &= ~DCERPC_PULL_BIGENDIAN;
 912         }
 913 
 914 
 915 req_done:
 916         /* we've got the full payload */
 917         req->state = RPC_REQUEST_DONE;
 918         DLIST_REMOVE(c->pending, req);
 919 
 920         if (c->request_queue != NULL) {
 921                 /* We have to look at shipping further requests before calling
 922                  * the async function, that one might close the pipe */
 923                 dcerpc_ship_next_request(c);
 924         }
 925 
 926         if (req->async.callback) {
 927                 req->async.callback(req);
 928         }
 929 }
 930 
 931 /*
 932   perform the send side of a async dcerpc request
 933 */
 934 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p, 
     /* [<][>][^][v][top][bottom][index][help] */
 935                                                const struct GUID *object,
 936                                                uint16_t opnum,
 937                                                bool async,
 938                                                DATA_BLOB *stub_data)
 939 {
 940         struct rpc_request *req;
 941 
 942         p->conn->transport.recv_data = dcerpc_recv_data;
 943 
 944         req = talloc(p, struct rpc_request);
 945         if (req == NULL) {
 946                 return NULL;
 947         }
 948 
 949         req->p = p;
 950         req->call_id = next_call_id(p->conn);
 951         req->status = NT_STATUS_OK;
 952         req->state = RPC_REQUEST_QUEUED;
 953         req->payload = data_blob(NULL, 0);
 954         req->flags = 0;
 955         req->fault_code = 0;
 956         req->async_call = async;
 957         req->ignore_timeout = false;
 958         req->async.callback = NULL;
 959         req->async.private_data = NULL;
 960         req->recv_handler = NULL;
 961 
 962         if (object != NULL) {
 963                 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
 964                 if (req->object == NULL) {
 965                         talloc_free(req);
 966                         return NULL;
 967                 }
 968         } else {
 969                 req->object = NULL;
 970         }
 971 
 972         req->opnum = opnum;
 973         req->request_data.length = stub_data->length;
 974         req->request_data.data = talloc_reference(req, stub_data->data);
 975         if (req->request_data.length && req->request_data.data == NULL) {
 976                 return NULL;
 977         }
 978 
 979         DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
 980         talloc_set_destructor(req, dcerpc_req_dequeue);
 981 
 982         dcerpc_ship_next_request(p->conn);
 983 
 984         if (p->request_timeout) {
 985                 event_add_timed(dcerpc_event_context(p), req, 
 986                                 timeval_current_ofs(p->request_timeout, 0), 
 987                                 dcerpc_timeout_handler, req);
 988         }
 989 
 990         return req;
 991 }
 992 
 993 /*
 994   Send a request using the transport
 995 */
 996 
 997 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
     /* [<][>][^][v][top][bottom][index][help] */
 998 {
 999         struct rpc_request *req;
1000         struct dcerpc_pipe *p;
1001         DATA_BLOB *stub_data;
1002         struct ncacn_packet pkt;
1003         DATA_BLOB blob;
1004         uint32_t remaining, chunk_size;
1005         bool first_packet = true;
1006         size_t sig_size = 0;
1007 
1008         req = c->request_queue;
1009         if (req == NULL) {
1010                 return;
1011         }
1012 
1013         p = req->p;
1014         stub_data = &req->request_data;
1015 
1016         if (!req->async_call && (c->pending != NULL)) {
1017                 return;
1018         }
1019 
1020         DLIST_REMOVE(c->request_queue, req);
1021         DLIST_ADD(c->pending, req);
1022         req->state = RPC_REQUEST_PENDING;
1023 
1024         init_ncacn_hdr(p->conn, &pkt);
1025 
1026         remaining = stub_data->length;
1027 
1028         /* we can write a full max_recv_frag size, minus the dcerpc
1029            request header size */
1030         chunk_size = p->conn->srv_max_recv_frag;
1031         chunk_size -= DCERPC_REQUEST_LENGTH;
1032         if (c->security_state.auth_info &&
1033             c->security_state.generic_state) {
1034                 sig_size = gensec_sig_size(c->security_state.generic_state,
1035                                            p->conn->srv_max_recv_frag);
1036                 if (sig_size) {
1037                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1038                         chunk_size -= sig_size;
1039                 }
1040         }
1041         chunk_size -= (chunk_size % 16);
1042 
1043         pkt.ptype = DCERPC_PKT_REQUEST;
1044         pkt.call_id = req->call_id;
1045         pkt.auth_length = 0;
1046         pkt.pfc_flags = 0;
1047         pkt.u.request.alloc_hint = remaining;
1048         pkt.u.request.context_id = p->context_id;
1049         pkt.u.request.opnum = req->opnum;
1050 
1051         if (req->object) {
1052                 pkt.u.request.object.object = *req->object;
1053                 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1054                 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1055         }
1056 
1057         /* we send a series of pdus without waiting for a reply */
1058         while (remaining > 0 || first_packet) {
1059                 uint32_t chunk = MIN(chunk_size, remaining);
1060                 bool last_frag = false;
1061 
1062                 first_packet = false;
1063                 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1064 
1065                 if (remaining == stub_data->length) {
1066                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1067                 }
1068                 if (chunk == remaining) {
1069                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1070                         last_frag = true;
1071                 }
1072 
1073                 pkt.u.request.stub_and_verifier.data = stub_data->data + 
1074                         (stub_data->length - remaining);
1075                 pkt.u.request.stub_and_verifier.length = chunk;
1076 
1077                 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1078                 if (!NT_STATUS_IS_OK(req->status)) {
1079                         req->state = RPC_REQUEST_DONE;
1080                         DLIST_REMOVE(p->conn->pending, req);
1081                         return;
1082                 }
1083                 
1084                 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1085                 if (!NT_STATUS_IS_OK(req->status)) {
1086                         req->state = RPC_REQUEST_DONE;
1087                         DLIST_REMOVE(p->conn->pending, req);
1088                         return;
1089                 }               
1090 
1091                 remaining -= chunk;
1092         }
1093 }
1094 
1095 /*
1096   return the event context for a dcerpc pipe
1097   used by callers who wish to operate asynchronously
1098 */
1099 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
     /* [<][>][^][v][top][bottom][index][help] */
1100 {
1101         return p->conn->event_ctx;
1102 }
1103 
1104 
1105 
1106 /*
1107   perform the receive side of a async dcerpc request
1108 */
1109 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
1110                              TALLOC_CTX *mem_ctx,
1111                              DATA_BLOB *stub_data)
1112 {
1113         NTSTATUS status;
1114 
1115         while (req->state != RPC_REQUEST_DONE) {
1116                 struct tevent_context *ctx = dcerpc_event_context(req->p);
1117                 if (event_loop_once(ctx) != 0) {
1118                         return NT_STATUS_CONNECTION_DISCONNECTED;
1119                 }
1120         }
1121         *stub_data = req->payload;
1122         status = req->status;
1123         if (stub_data->data) {
1124                 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1125         }
1126         if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1127                 req->p->last_fault_code = req->fault_code;
1128         }
1129         talloc_free(req);
1130         return status;
1131 }
1132 
1133 /*
1134   perform a full request/response pair on a dcerpc pipe
1135 */
1136 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
     /* [<][>][^][v][top][bottom][index][help] */
1137                         struct GUID *object,
1138                         uint16_t opnum,
1139                         bool async,
1140                         TALLOC_CTX *mem_ctx,
1141                         DATA_BLOB *stub_data_in,
1142                         DATA_BLOB *stub_data_out)
1143 {
1144         struct rpc_request *req;
1145 
1146         req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1147         if (req == NULL) {
1148                 return NT_STATUS_NO_MEMORY;
1149         }
1150 
1151         return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1152 }
1153 
1154 
1155 /*
1156   this is a paranoid NDR validator. For every packet we push onto the wire
1157   we pull it back again, then push it again. Then we compare the raw NDR data
1158   for that to the NDR we initially generated. If they don't match then we know
1159   we must have a bug in either the pull or push side of our code
1160 */
1161 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c, 
     /* [<][>][^][v][top][bottom][index][help] */
1162                                        TALLOC_CTX *mem_ctx,
1163                                        DATA_BLOB blob,
1164                                        size_t struct_size,
1165                                        ndr_push_flags_fn_t ndr_push,
1166                                        ndr_pull_flags_fn_t ndr_pull)
1167 {
1168         void *st;
1169         struct ndr_pull *pull;
1170         struct ndr_push *push;
1171         DATA_BLOB blob2;
1172         enum ndr_err_code ndr_err;
1173 
1174         st = talloc_size(mem_ctx, struct_size);
1175         if (!st) {
1176                 return NT_STATUS_NO_MEMORY;
1177         }
1178 
1179         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1180         if (!pull) {
1181                 return NT_STATUS_NO_MEMORY;
1182         }
1183         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1184 
1185         ndr_err = ndr_pull(pull, NDR_IN, st);
1186         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1187                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1188                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1189                                          "failed input validation pull - %s",
1190                                          nt_errstr(status));
1191                 return ndr_map_error2ntstatus(ndr_err);
1192         }
1193 
1194         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1195         if (!push) {
1196                 return NT_STATUS_NO_MEMORY;
1197         }       
1198 
1199         ndr_err = ndr_push(push, NDR_IN, st);
1200         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1202                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1203                                          "failed input validation push - %s",
1204                                          nt_errstr(status));
1205                 return ndr_map_error2ntstatus(ndr_err);
1206         }
1207 
1208         blob2 = ndr_push_blob(push);
1209 
1210         if (data_blob_cmp(&blob, &blob2) != 0) {
1211                 DEBUG(3,("original:\n"));
1212                 dump_data(3, blob.data, blob.length);
1213                 DEBUG(3,("secondary:\n"));
1214                 dump_data(3, blob2.data, blob2.length);
1215                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216                                          "failed input validation blobs doesn't match");
1217                 return ndr_map_error2ntstatus(ndr_err);
1218         }
1219 
1220         return NT_STATUS_OK;
1221 }
1222 
1223 /*
1224   this is a paranoid NDR input validator. For every packet we pull
1225   from the wire we push it back again then pull and push it
1226   again. Then we compare the raw NDR data for that to the NDR we
1227   initially generated. If they don't match then we know we must have a
1228   bug in either the pull or push side of our code
1229 */
1230 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
     /* [<][>][^][v][top][bottom][index][help] */
1231                                         struct ndr_pull *pull_in,
1232                                         void *struct_ptr,
1233                                         size_t struct_size,
1234                                         ndr_push_flags_fn_t ndr_push,
1235                                         ndr_pull_flags_fn_t ndr_pull,
1236                                         ndr_print_function_t ndr_print)
1237 {
1238         void *st;
1239         struct ndr_pull *pull;
1240         struct ndr_push *push;
1241         DATA_BLOB blob, blob2;
1242         TALLOC_CTX *mem_ctx = pull_in;
1243         char *s1, *s2;
1244         enum ndr_err_code ndr_err;
1245 
1246         st = talloc_size(mem_ctx, struct_size);
1247         if (!st) {
1248                 return NT_STATUS_NO_MEMORY;
1249         }
1250         memcpy(st, struct_ptr, struct_size);
1251 
1252         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1253         if (!push) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }       
1256 
1257         ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1258         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1259                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1260                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1261                                          "failed output validation push - %s",
1262                                          nt_errstr(status));
1263                 return ndr_map_error2ntstatus(ndr_err);
1264         }
1265 
1266         blob = ndr_push_blob(push);
1267 
1268         pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1269         if (!pull) {
1270                 return NT_STATUS_NO_MEMORY;
1271         }
1272 
1273         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1274         ndr_err = ndr_pull(pull, NDR_OUT, st);
1275         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1276                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1277                 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1278                                          "failed output validation pull - %s",
1279                                          nt_errstr(status));
1280                 return ndr_map_error2ntstatus(ndr_err);
1281         }
1282 
1283         push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1284         if (!push) {
1285                 return NT_STATUS_NO_MEMORY;
1286         }       
1287 
1288         ndr_err = ndr_push(push, NDR_OUT, st);
1289         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1290                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1291                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1292                                          "failed output validation push2 - %s",
1293                                          nt_errstr(status));
1294                 return ndr_map_error2ntstatus(ndr_err);
1295         }
1296 
1297         blob2 = ndr_push_blob(push);
1298 
1299         if (data_blob_cmp(&blob, &blob2) != 0) {
1300                 DEBUG(3,("original:\n"));
1301                 dump_data(3, blob.data, blob.length);
1302                 DEBUG(3,("secondary:\n"));
1303                 dump_data(3, blob2.data, blob2.length);
1304                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1305                                          "failed output validation blobs doesn't match");
1306                 return ndr_map_error2ntstatus(ndr_err);
1307         }
1308 
1309         /* this checks the printed forms of the two structures, which effectively
1310            tests all of the value() attributes */
1311         s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1312                                        NDR_OUT, struct_ptr);
1313         s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE", 
1314                                        NDR_OUT, st);
1315         if (strcmp(s1, s2) != 0) {
1316 #if 1
1317                 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1318 #else
1319                 /* this is sometimes useful */
1320                 printf("VALIDATE ERROR\n");
1321                 file_save("wire.dat", s1, strlen(s1));
1322                 file_save("gen.dat", s2, strlen(s2));
1323                 system("diff -u wire.dat gen.dat");
1324 #endif
1325                 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1326                                          "failed output validation strings doesn't match");
1327                 return ndr_map_error2ntstatus(ndr_err);
1328         }
1329 
1330         return NT_STATUS_OK;
1331 }
1332 
1333 
1334 /**
1335  send a rpc request given a dcerpc_call structure 
1336  */
1337 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
     /* [<][>][^][v][top][bottom][index][help] */
1338                                                 const struct GUID *object,
1339                                                 const struct ndr_interface_table *table,
1340                                                 uint32_t opnum, 
1341                                                 TALLOC_CTX *mem_ctx, 
1342                                                 void *r)
1343 {
1344         const struct ndr_interface_call *call;
1345         struct ndr_push *push;
1346         NTSTATUS status;
1347         DATA_BLOB request;
1348         struct rpc_request *req;
1349         enum ndr_err_code ndr_err;
1350 
1351         call = &table->calls[opnum];
1352 
1353         /* setup for a ndr_push_* call */
1354         push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1355         if (!push) {
1356                 return NULL;
1357         }
1358 
1359         if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1360                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1361         }
1362 
1363         /* push the structure into a blob */
1364         ndr_err = call->ndr_push(push, NDR_IN, r);
1365         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1366                 status = ndr_map_error2ntstatus(ndr_err);
1367                 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1368                          nt_errstr(status)));
1369                 talloc_free(push);
1370                 return NULL;
1371         }
1372 
1373         /* retrieve the blob */
1374         request = ndr_push_blob(push);
1375 
1376         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1377                 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size, 
1378                                                 call->ndr_push, call->ndr_pull);
1379                 if (!NT_STATUS_IS_OK(status)) {
1380                         DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1381                                  nt_errstr(status)));
1382                         talloc_free(push);
1383                         return NULL;
1384                 }
1385         }
1386 
1387         DEBUG(10,("rpc request data:\n"));
1388         dump_data(10, request.data, request.length);
1389 
1390         /* make the actual dcerpc request */
1391         req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1392                                   &request);
1393 
1394         if (req != NULL) {
1395                 req->ndr.table = table;
1396                 req->ndr.opnum = opnum;
1397                 req->ndr.struct_ptr = r;
1398                 req->ndr.mem_ctx = mem_ctx;
1399         }
1400 
1401         talloc_free(push);
1402 
1403         return req;
1404 }
1405 
1406 /*
1407   receive the answer from a dcerpc_ndr_request_send()
1408 */
1409 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1410 {
1411         struct dcerpc_pipe *p = req->p;
1412         NTSTATUS status;
1413         DATA_BLOB response;
1414         struct ndr_pull *pull;
1415         uint_t flags;
1416         TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1417         void *r = req->ndr.struct_ptr;
1418         uint32_t opnum = req->ndr.opnum;
1419         const struct ndr_interface_table *table = req->ndr.table;
1420         const struct ndr_interface_call *call = &table->calls[opnum];
1421         enum ndr_err_code ndr_err;
1422 
1423         /* make sure the recv code doesn't free the request, as we
1424            need to grab the flags element before it is freed */
1425         if (talloc_reference(p, req) == NULL) {
1426                 return NT_STATUS_NO_MEMORY;
1427         }
1428 
1429         status = dcerpc_request_recv(req, mem_ctx, &response);
1430         if (!NT_STATUS_IS_OK(status)) {
1431                 talloc_unlink(p, req);
1432                 return status;
1433         }
1434 
1435         flags = req->flags;
1436 
1437         /* prepare for ndr_pull_* */
1438         pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1439         if (!pull) {
1440                 talloc_unlink(p, req);
1441                 return NT_STATUS_NO_MEMORY;
1442         }
1443 
1444         if (pull->data) {
1445                 pull->data = talloc_steal(pull, pull->data);
1446         }
1447         talloc_unlink(p, req);
1448 
1449         if (flags & DCERPC_PULL_BIGENDIAN) {
1450                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1451         }
1452 
1453         DEBUG(10,("rpc reply data:\n"));
1454         dump_data(10, pull->data, pull->data_size);
1455 
1456         /* pull the structure from the blob */
1457         ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1458         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1459                 status = ndr_map_error2ntstatus(ndr_err);
1460                 dcerpc_log_packet(p->conn->packet_log_dir,
1461                                                   table, opnum, NDR_OUT, 
1462                                                   &response);
1463                 return status;
1464         }
1465 
1466         if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1467                 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size, 
1468                                                  call->ndr_push, call->ndr_pull, 
1469                                                  call->ndr_print);
1470                 if (!NT_STATUS_IS_OK(status)) {
1471                         dcerpc_log_packet(p->conn->packet_log_dir, 
1472                                                           table, opnum, NDR_OUT, 
1473                                   &response);
1474                         return status;
1475                 }
1476         }
1477 
1478         if (pull->offset != pull->data_size) {
1479                 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n", 
1480                          pull->data_size - pull->offset));
1481                 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1482                    but it turns out that early versions of NT
1483                    (specifically NT3.1) add junk onto the end of rpc
1484                    packets, so if we want to interoperate at all with
1485                    those versions then we need to ignore this error */
1486         }
1487 
1488         /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1489 
1490         return NT_STATUS_OK;
1491 }
1492 
1493 
1494 /*
1495   a useful helper function for synchronous rpc requests 
1496 
1497   this can be used when you have ndr push/pull functions in the
1498   standard format
1499 */
1500 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
     /* [<][>][^][v][top][bottom][index][help] */
1501                             const struct GUID *object,
1502                             const struct ndr_interface_table *table,
1503                             uint32_t opnum, 
1504                             TALLOC_CTX *mem_ctx, 
1505                             void *r)
1506 {
1507         struct rpc_request *req;
1508 
1509         req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1510         if (req == NULL) {
1511                 return NT_STATUS_NO_MEMORY;
1512         }
1513 
1514         return dcerpc_ndr_request_recv(req);
1515 }
1516 
1517 
1518 /*
1519   a useful function for retrieving the server name we connected to
1520 */
1521 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
     /* [<][>][^][v][top][bottom][index][help] */
1522 {
1523         if (!p->conn->transport.target_hostname) {
1524                 if (!p->conn->transport.peer_name) {
1525                         return "";
1526                 }
1527                 return p->conn->transport.peer_name(p->conn);
1528         }
1529         return p->conn->transport.target_hostname(p->conn);
1530 }
1531 
1532 
1533 /*
1534   get the dcerpc auth_level for a open connection
1535 */
1536 uint32_t dcerpc_auth_level(struct dcerpc_connection *c) 
     /* [<][>][^][v][top][bottom][index][help] */
1537 {
1538         uint8_t auth_level;
1539 
1540         if (c->flags & DCERPC_SEAL) {
1541                 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1542         } else if (c->flags & DCERPC_SIGN) {
1543                 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1544         } else if (c->flags & DCERPC_CONNECT) {
1545                 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1546         } else {
1547                 auth_level = DCERPC_AUTH_LEVEL_NONE;
1548         }
1549         return auth_level;
1550 }
1551 
1552 /*
1553   Receive an alter reply from the transport
1554 */
1555 static void dcerpc_alter_recv_handler(struct rpc_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
1556                                       DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1557 {
1558         struct composite_context *c;
1559         struct dcerpc_pipe *recv_pipe;
1560 
1561         c = talloc_get_type(req->async.private_data, struct composite_context);
1562         recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1563 
1564         if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1565             pkt->u.alter_resp.num_results == 1 &&
1566             pkt->u.alter_resp.ctx_list[0].result != 0) {
1567                 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
1568                          pkt->u.alter_resp.ctx_list[0].reason));
1569                 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1570                 return;
1571         }
1572 
1573         if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1574             pkt->u.alter_resp.num_results == 0 ||
1575             pkt->u.alter_resp.ctx_list[0].result != 0) {
1576                 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1577                 return;
1578         }
1579 
1580         /* the alter_resp might contain a reply set of credentials */
1581         if (recv_pipe->conn->security_state.auth_info &&
1582             pkt->u.alter_resp.auth_info.length) {
1583                 enum ndr_err_code ndr_err;
1584                 ndr_err = ndr_pull_struct_blob(
1585                         &pkt->u.alter_resp.auth_info, recv_pipe,
1586                         NULL,
1587                         recv_pipe->conn->security_state.auth_info,
1588                         (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1589                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1590                         c->status = ndr_map_error2ntstatus(ndr_err);
1591                         if (!composite_is_ok(c)) return;
1592                 }
1593         }
1594 
1595         composite_done(c);
1596 }
1597 
1598 /* 
1599    send a dcerpc alter_context request
1600 */
1601 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p, 
     /* [<][>][^][v][top][bottom][index][help] */
1602                                                     TALLOC_CTX *mem_ctx,
1603                                                     const struct ndr_syntax_id *syntax,
1604                                                     const struct ndr_syntax_id *transfer_syntax)
1605 {
1606         struct composite_context *c;
1607         struct ncacn_packet pkt;
1608         DATA_BLOB blob;
1609         struct rpc_request *req;
1610 
1611         c = composite_create(mem_ctx, p->conn->event_ctx);
1612         if (c == NULL) return NULL;
1613 
1614         c->private_data = p;
1615 
1616         p->syntax = *syntax;
1617         p->transfer_syntax = *transfer_syntax;
1618 
1619         init_ncacn_hdr(p->conn, &pkt);
1620 
1621         pkt.ptype = DCERPC_PKT_ALTER;
1622         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1623         pkt.call_id = p->conn->call_id;
1624         pkt.auth_length = 0;
1625 
1626         if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1627                 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1628         }
1629 
1630         if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1631                 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1632         }
1633 
1634         pkt.u.alter.max_xmit_frag = 5840;
1635         pkt.u.alter.max_recv_frag = 5840;
1636         pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1637         pkt.u.alter.num_contexts = 1;
1638         pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1639         if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1640         pkt.u.alter.ctx_list[0].context_id = p->context_id;
1641         pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1642         pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1643         pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1644         pkt.u.alter.auth_info = data_blob(NULL, 0);
1645 
1646         /* construct the NDR form of the packet */
1647         c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1648                                     p->conn->security_state.auth_info);
1649         if (!composite_is_ok(c)) return c;
1650 
1651         p->conn->transport.recv_data = dcerpc_recv_data;
1652 
1653         /*
1654          * we allocate a dcerpc_request so we can be in the same
1655          * request queue as normal requests
1656          */
1657         req = talloc_zero(c, struct rpc_request);
1658         if (composite_nomem(req, c)) return c;
1659 
1660         req->state = RPC_REQUEST_PENDING;
1661         req->call_id = pkt.call_id;
1662         req->async.private_data = c;
1663         req->async.callback = dcerpc_composite_fail;
1664         req->p = p;
1665         req->recv_handler = dcerpc_alter_recv_handler;
1666         DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1667         talloc_set_destructor(req, dcerpc_req_dequeue);
1668 
1669         c->status = p->conn->transport.send_request(p->conn, &blob, true);
1670         if (!composite_is_ok(c)) return c;
1671 
1672         event_add_timed(c->event_ctx, req,
1673                         timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1674                         dcerpc_timeout_handler, req);
1675 
1676         return c;
1677 }
1678 
1679 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1680 {
1681         NTSTATUS result = composite_wait(ctx);
1682         talloc_free(ctx);
1683         return result;
1684 }
1685 
1686 /* 
1687    send a dcerpc alter_context request
1688 */
1689 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p, 
     /* [<][>][^][v][top][bottom][index][help] */
1690                               TALLOC_CTX *mem_ctx,
1691                               const struct ndr_syntax_id *syntax,
1692                               const struct ndr_syntax_id *transfer_syntax)
1693 {
1694         struct composite_context *creq;
1695         creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1696         return dcerpc_alter_context_recv(creq);
1697 }

/* [<][>][^][v][top][bottom][index][help] */