root/source4/rpc_server/dcerpc_server.c

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

DEFINITIONS

This source file includes following definitions.
  1. endpoints_match
  2. find_endpoint
  3. dcesrv_find_context
  4. interface_match
  5. find_interface
  6. interface_match_by_uuid
  7. find_interface_by_uuid
  8. dcesrv_find_fragmented_call
  9. dcesrv_interface_register
  10. dcesrv_inherited_session_key
  11. dcesrv_generic_session_key
  12. dcesrv_fetch_session_key
  13. dcesrv_endpoint_connect
  14. dcesrv_endpoint_search_connect
  15. dcesrv_init_hdr
  16. dcesrv_call_set_list
  17. dcesrv_fault
  18. dcesrv_bind_nak
  19. dcesrv_connection_context_destructor
  20. dcesrv_bind
  21. dcesrv_auth3
  22. dcesrv_alter_new_context
  23. dcesrv_alter
  24. dcesrv_request
  25. dcesrv_reply
  26. dcesrv_connection_get_my_addr
  27. dcesrv_connection_get_peer_addr
  28. dce_full_packet
  29. dce_partial_advance
  30. dcesrv_call_dequeue
  31. dcesrv_input_process
  32. dcesrv_input
  33. dcesrv_output
  34. dcesrv_init_context
  35. dcerpc_register_ep_server
  36. dcesrv_ep_server_byname
  37. dcerpc_server_init
  38. dcerpc_module_version
  39. dcesrv_init_ipc_context

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    server side dcerpc core code
   5 
   6    Copyright (C) Andrew Tridgell 2003-2005
   7    Copyright (C) Stefan (metze) Metzmacher 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 "librpc/gen_ndr/ndr_dcerpc.h"
  25 #include "auth/auth.h"
  26 #include "auth/gensec/gensec.h"
  27 #include "../lib/util/dlinklist.h"
  28 #include "rpc_server/dcerpc_server.h"
  29 #include "rpc_server/dcerpc_server_proto.h"
  30 #include "librpc/rpc/dcerpc_proto.h"
  31 #include "lib/events/events.h"
  32 #include "smbd/service_task.h"
  33 #include "smbd/service_stream.h"
  34 #include "smbd/service.h"
  35 #include "system/filesys.h"
  36 #include "libcli/security/security.h"
  37 #include "param/param.h"
  38 
  39 #define SAMBA_ASSOC_GROUP 0x12345678
  40 
  41 extern const struct dcesrv_interface dcesrv_mgmt_interface;
  42 
  43 /*
  44   see if two endpoints match
  45 */
  46 static bool endpoints_match(const struct dcerpc_binding *ep1,
     /* [<][>][^][v][top][bottom][index][help] */
  47                             const struct dcerpc_binding *ep2)
  48 {
  49         if (ep1->transport != ep2->transport) {
  50                 return false;
  51         }
  52 
  53         if (!ep1->endpoint || !ep2->endpoint) {
  54                 return ep1->endpoint == ep2->endpoint;
  55         }
  56 
  57         if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
  58                 return false;
  59 
  60         return true;
  61 }
  62 
  63 /*
  64   find an endpoint in the dcesrv_context
  65 */
  66 static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  67                                              const struct dcerpc_binding *ep_description)
  68 {
  69         struct dcesrv_endpoint *ep;
  70         for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
  71                 if (endpoints_match(ep->ep_description, ep_description)) {
  72                         return ep;
  73                 }
  74         }
  75         return NULL;
  76 }
  77 
  78 /*
  79   find a registered context_id from a bind or alter_context
  80 */
  81 static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_connection *conn, 
     /* [<][>][^][v][top][bottom][index][help] */
  82                                                                    uint32_t context_id)
  83 {
  84         struct dcesrv_connection_context *c;
  85         for (c=conn->contexts;c;c=c->next) {
  86                 if (c->context_id == context_id) return c;
  87         }
  88         return NULL;
  89 }
  90 
  91 /*
  92   see if a uuid and if_version match to an interface
  93 */
  94 static bool interface_match(const struct dcesrv_interface *if1,
     /* [<][>][^][v][top][bottom][index][help] */
  95                                                         const struct dcesrv_interface *if2)
  96 {
  97         return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
  98                         GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
  99 }
 100 
 101 /*
 102   find the interface operations on an endpoint
 103 */
 104 static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoint *endpoint,
     /* [<][>][^][v][top][bottom][index][help] */
 105                                                      const struct dcesrv_interface *iface)
 106 {
 107         struct dcesrv_if_list *ifl;
 108         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
 109                 if (interface_match(&(ifl->iface), iface)) {
 110                         return &(ifl->iface);
 111                 }
 112         }
 113         return NULL;
 114 }
 115 
 116 /*
 117   see if a uuid and if_version match to an interface
 118 */
 119 static bool interface_match_by_uuid(const struct dcesrv_interface *iface,
     /* [<][>][^][v][top][bottom][index][help] */
 120                                     const struct GUID *uuid, uint32_t if_version)
 121 {
 122         return (iface->syntax_id.if_version == if_version && 
 123                         GUID_equal(&iface->syntax_id.uuid, uuid));
 124 }
 125 
 126 /*
 127   find the interface operations on an endpoint by uuid
 128 */
 129 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
     /* [<][>][^][v][top][bottom][index][help] */
 130                                                              const struct GUID *uuid, uint32_t if_version)
 131 {
 132         struct dcesrv_if_list *ifl;
 133         for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
 134                 if (interface_match_by_uuid(&(ifl->iface), uuid, if_version)) {
 135                         return &(ifl->iface);
 136                 }
 137         }
 138         return NULL;
 139 }
 140 
 141 /*
 142   find the earlier parts of a fragmented call awaiting reassembily
 143 */
 144 static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
     /* [<][>][^][v][top][bottom][index][help] */
 145 {
 146         struct dcesrv_call_state *c;
 147         for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
 148                 if (c->pkt.call_id == call_id) {
 149                         return c;
 150                 }
 151         }
 152         return NULL;
 153 }
 154 
 155 /*
 156   register an interface on an endpoint
 157 */
 158 _PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 159                                    const char *ep_name,
 160                                    const struct dcesrv_interface *iface,
 161                                    const struct security_descriptor *sd)
 162 {
 163         struct dcesrv_endpoint *ep;
 164         struct dcesrv_if_list *ifl;
 165         struct dcerpc_binding *binding;
 166         bool add_ep = false;
 167         NTSTATUS status;
 168         
 169         status = dcerpc_parse_binding(dce_ctx, ep_name, &binding);
 170 
 171         if (NT_STATUS_IS_ERR(status)) {
 172                 DEBUG(0, ("Trouble parsing binding string '%s'\n", ep_name));
 173                 return status;
 174         }
 175 
 176         /* check if this endpoint exists
 177          */
 178         if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
 179                 ep = talloc(dce_ctx, struct dcesrv_endpoint);
 180                 if (!ep) {
 181                         return NT_STATUS_NO_MEMORY;
 182                 }
 183                 ZERO_STRUCTP(ep);
 184                 ep->ep_description = talloc_reference(ep, binding);
 185                 add_ep = true;
 186 
 187                 /* add mgmt interface */
 188                 ifl = talloc(dce_ctx, struct dcesrv_if_list);
 189                 if (!ifl) {
 190                         return NT_STATUS_NO_MEMORY;
 191                 }
 192 
 193                 memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
 194                            sizeof(struct dcesrv_interface));
 195 
 196                 DLIST_ADD(ep->interface_list, ifl);
 197         }
 198 
 199         /* see if the interface is already registered on te endpoint */
 200         if (find_interface(ep, iface)!=NULL) {
 201                 DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
 202                         iface->name, ep_name));
 203                 return NT_STATUS_OBJECT_NAME_COLLISION;
 204         }
 205 
 206         /* talloc a new interface list element */
 207         ifl = talloc(dce_ctx, struct dcesrv_if_list);
 208         if (!ifl) {
 209                 return NT_STATUS_NO_MEMORY;
 210         }
 211 
 212         /* copy the given interface struct to the one on the endpoints interface list */
 213         memcpy(&(ifl->iface),iface, sizeof(struct dcesrv_interface));
 214 
 215         /* if we have a security descriptor given,
 216          * we should see if we can set it up on the endpoint
 217          */
 218         if (sd != NULL) {
 219                 /* if there's currently no security descriptor given on the endpoint
 220                  * we try to set it
 221                  */
 222                 if (ep->sd == NULL) {
 223                         ep->sd = security_descriptor_copy(dce_ctx, sd);
 224                 }
 225 
 226                 /* if now there's no security descriptor given on the endpoint
 227                  * something goes wrong, either we failed to copy the security descriptor
 228                  * or there was already one on the endpoint
 229                  */
 230                 if (ep->sd != NULL) {
 231                         DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
 232                                  "                           on endpoint '%s'\n",
 233                                 iface->name, ep_name));
 234                         if (add_ep) free(ep);
 235                         free(ifl);
 236                         return NT_STATUS_OBJECT_NAME_COLLISION;
 237                 }
 238         }
 239 
 240         /* finally add the interface on the endpoint */
 241         DLIST_ADD(ep->interface_list, ifl);
 242 
 243         /* if it's a new endpoint add it to the dcesrv_context */
 244         if (add_ep) {
 245                 DLIST_ADD(dce_ctx->endpoint_list, ep);
 246         }
 247 
 248         DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
 249                 iface->name, ep_name));
 250 
 251         return NT_STATUS_OK;
 252 }
 253 
 254 NTSTATUS dcesrv_inherited_session_key(struct dcesrv_connection *p,
     /* [<][>][^][v][top][bottom][index][help] */
 255                                       DATA_BLOB *session_key)
 256 {
 257         if (p->auth_state.session_info->session_key.length) {
 258                 *session_key = p->auth_state.session_info->session_key;
 259                 return NT_STATUS_OK;
 260         }
 261         return NT_STATUS_NO_USER_SESSION_KEY;
 262 }
 263 
 264 NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
     /* [<][>][^][v][top][bottom][index][help] */
 265                                     DATA_BLOB *session_key)
 266 {
 267         /* this took quite a few CPU cycles to find ... */
 268         session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
 269         session_key->length = 16;
 270         return NT_STATUS_OK;
 271 }
 272 
 273 /*
 274   fetch the user session key - may be default (above) or the SMB session key
 275 
 276   The key is always truncated to 16 bytes 
 277 */
 278 _PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
     /* [<][>][^][v][top][bottom][index][help] */
 279                                   DATA_BLOB *session_key)
 280 {
 281         NTSTATUS status = p->auth_state.session_key(p, session_key);
 282         if (!NT_STATUS_IS_OK(status)) {
 283                 return status;
 284         }
 285 
 286         session_key->length = MIN(session_key->length, 16);
 287 
 288         return NT_STATUS_OK;
 289 }
 290 
 291 /*
 292   connect to a dcerpc endpoint
 293 */
 294 _PUBLIC_ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 295                                  TALLOC_CTX *mem_ctx,
 296                                  const struct dcesrv_endpoint *ep,
 297                                  struct auth_session_info *session_info,
 298                                  struct tevent_context *event_ctx,
 299                                  struct messaging_context *msg_ctx,
 300                                  struct server_id server_id,
 301                                  uint32_t state_flags,
 302                                  struct dcesrv_connection **_p)
 303 {
 304         struct dcesrv_connection *p;
 305 
 306         if (!session_info) {
 307                 return NT_STATUS_ACCESS_DENIED;
 308         }
 309 
 310         p = talloc(mem_ctx, struct dcesrv_connection);
 311         NT_STATUS_HAVE_NO_MEMORY(p);
 312 
 313         if (!talloc_reference(p, session_info)) {
 314                 talloc_free(p);
 315                 return NT_STATUS_NO_MEMORY;
 316         }
 317 
 318         p->dce_ctx = dce_ctx;
 319         p->endpoint = ep;
 320         p->contexts = NULL;
 321         p->call_list = NULL;
 322         p->packet_log_dir = lp_lockdir(dce_ctx->lp_ctx);
 323         p->incoming_fragmented_call_list = NULL;
 324         p->pending_call_list = NULL;
 325         p->cli_max_recv_frag = 0;
 326         p->partial_input = data_blob(NULL, 0);
 327         p->auth_state.auth_info = NULL;
 328         p->auth_state.gensec_security = NULL;
 329         p->auth_state.session_info = session_info;
 330         p->auth_state.session_key = dcesrv_generic_session_key;
 331         p->event_ctx = event_ctx;
 332         p->msg_ctx = msg_ctx;
 333         p->server_id = server_id;
 334         p->processing = false;
 335         p->state_flags = state_flags;
 336         ZERO_STRUCT(p->transport);
 337 
 338         *_p = p;
 339         return NT_STATUS_OK;
 340 }
 341 
 342 /*
 343   search and connect to a dcerpc endpoint
 344 */
 345 _PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 346                                         TALLOC_CTX *mem_ctx,
 347                                         const struct dcerpc_binding *ep_description,
 348                                         struct auth_session_info *session_info,
 349                                         struct tevent_context *event_ctx,
 350                                         struct messaging_context *msg_ctx,
 351                                         struct server_id server_id,
 352                                         uint32_t state_flags,
 353                                         struct dcesrv_connection **dce_conn_p)
 354 {
 355         NTSTATUS status;
 356         const struct dcesrv_endpoint *ep;
 357 
 358         /* make sure this endpoint exists */
 359         ep = find_endpoint(dce_ctx, ep_description);
 360         if (!ep) {
 361                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 362         }
 363 
 364         status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
 365                                          event_ctx, msg_ctx, server_id,
 366                                          state_flags, dce_conn_p);
 367         NT_STATUS_NOT_OK_RETURN(status);
 368 
 369         (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
 370 
 371         /* TODO: check security descriptor of the endpoint here 
 372          *       if it's a smb named pipe
 373          *       if it's failed free dce_conn_p
 374          */
 375 
 376         return NT_STATUS_OK;
 377 }
 378 
 379 
 380 static void dcesrv_init_hdr(struct ncacn_packet *pkt, bool bigendian)
     /* [<][>][^][v][top][bottom][index][help] */
 381 {
 382         pkt->rpc_vers = 5;
 383         pkt->rpc_vers_minor = 0;
 384         if (bigendian) {
 385                 pkt->drep[0] = 0;
 386         } else {
 387                 pkt->drep[0] = DCERPC_DREP_LE;
 388         }
 389         pkt->drep[1] = 0;
 390         pkt->drep[2] = 0;
 391         pkt->drep[3] = 0;
 392 }
 393 
 394 /*
 395   move a call from an existing linked list to the specified list. This
 396   prevents bugs where we forget to remove the call from a previous
 397   list when moving it.
 398  */
 399 static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
     /* [<][>][^][v][top][bottom][index][help] */
 400                                  enum dcesrv_call_list list)
 401 {
 402         switch (call->list) {
 403         case DCESRV_LIST_NONE:
 404                 break;
 405         case DCESRV_LIST_CALL_LIST:
 406                 DLIST_REMOVE(call->conn->call_list, call);
 407                 break;
 408         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
 409                 DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
 410                 break;
 411         case DCESRV_LIST_PENDING_CALL_LIST:
 412                 DLIST_REMOVE(call->conn->pending_call_list, call);
 413                 break;
 414         }
 415         call->list = list;
 416         switch (list) {
 417         case DCESRV_LIST_NONE:
 418                 break;
 419         case DCESRV_LIST_CALL_LIST:
 420                 DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
 421                 break;
 422         case DCESRV_LIST_FRAGMENTED_CALL_LIST:
 423                 DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
 424                 break;
 425         case DCESRV_LIST_PENDING_CALL_LIST:
 426                 DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
 427                 break;
 428         }
 429 }
 430 
 431 /*
 432   return a dcerpc fault
 433 */
 434 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
     /* [<][>][^][v][top][bottom][index][help] */
 435 {
 436         struct ncacn_packet pkt;
 437         struct data_blob_list_item *rep;
 438         uint8_t zeros[4];
 439         NTSTATUS status;
 440 
 441         /* setup a bind_ack */
 442         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 443         pkt.auth_length = 0;
 444         pkt.call_id = call->pkt.call_id;
 445         pkt.ptype = DCERPC_PKT_FAULT;
 446         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 447         pkt.u.fault.alloc_hint = 0;
 448         pkt.u.fault.context_id = 0;
 449         pkt.u.fault.cancel_count = 0;
 450         pkt.u.fault.status = fault_code;
 451 
 452         ZERO_STRUCT(zeros);
 453         pkt.u.fault._pad = data_blob_const(zeros, sizeof(zeros));
 454 
 455         rep = talloc(call, struct data_blob_list_item);
 456         if (!rep) {
 457                 return NT_STATUS_NO_MEMORY;
 458         }
 459 
 460         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
 461         if (!NT_STATUS_IS_OK(status)) {
 462                 return status;
 463         }
 464 
 465         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 466 
 467         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 468         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 469 
 470         return NT_STATUS_OK;    
 471 }
 472 
 473 
 474 /*
 475   return a dcerpc bind_nak
 476 */
 477 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
     /* [<][>][^][v][top][bottom][index][help] */
 478 {
 479         struct ncacn_packet pkt;
 480         struct data_blob_list_item *rep;
 481         NTSTATUS status;
 482 
 483         /* setup a bind_nak */
 484         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 485         pkt.auth_length = 0;
 486         pkt.call_id = call->pkt.call_id;
 487         pkt.ptype = DCERPC_PKT_BIND_NAK;
 488         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 489         pkt.u.bind_nak.reject_reason = reason;
 490         if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
 491                 pkt.u.bind_nak.versions.v.num_versions = 0;
 492         }
 493 
 494         rep = talloc(call, struct data_blob_list_item);
 495         if (!rep) {
 496                 return NT_STATUS_NO_MEMORY;
 497         }
 498 
 499         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, NULL);
 500         if (!NT_STATUS_IS_OK(status)) {
 501                 return status;
 502         }
 503 
 504         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 505 
 506         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 507         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 508 
 509         return NT_STATUS_OK;    
 510 }
 511 
 512 static int dcesrv_connection_context_destructor(struct dcesrv_connection_context *c)
     /* [<][>][^][v][top][bottom][index][help] */
 513 {
 514         DLIST_REMOVE(c->conn->contexts, c);
 515 
 516         if (c->iface) {
 517                 c->iface->unbind(c, c->iface);
 518         }
 519 
 520         return 0;
 521 }
 522 
 523 /*
 524   handle a bind request
 525 */
 526 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
     /* [<][>][^][v][top][bottom][index][help] */
 527 {
 528         uint32_t if_version, transfer_syntax_version;
 529         struct GUID uuid, *transfer_syntax_uuid;
 530         struct ncacn_packet pkt;
 531         struct data_blob_list_item *rep;
 532         NTSTATUS status;
 533         uint32_t result=0, reason=0;
 534         uint32_t context_id;
 535         const struct dcesrv_interface *iface;
 536         uint32_t extra_flags = 0;
 537 
 538         /*
 539          * Association groups allow policy handles to be shared across
 540          * multiple client connections.  We don't implement this yet.
 541          *
 542          * So we just allow 0 if the client wants to create a new
 543          * association group.
 544          *
 545          * And we allow the 0x12345678 value, we give away as
 546          * assoc_group_id back to the clients
 547          */
 548         if (call->pkt.u.bind.assoc_group_id != 0 &&
 549             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
 550             call->pkt.u.bind.assoc_group_id != SAMBA_ASSOC_GROUP) {
 551                 return dcesrv_bind_nak(call, 0);        
 552         }
 553 
 554         if (call->pkt.u.bind.num_contexts < 1 ||
 555             call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
 556                 return dcesrv_bind_nak(call, 0);
 557         }
 558 
 559         context_id = call->pkt.u.bind.ctx_list[0].context_id;
 560 
 561         /* you can't bind twice on one context */
 562         if (dcesrv_find_context(call->conn, context_id) != NULL) {
 563                 return dcesrv_bind_nak(call, 0);
 564         }
 565 
 566         if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
 567         uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
 568 
 569         transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
 570         transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
 571         if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
 572             ndr_transfer_syntax.if_version != transfer_syntax_version) {
 573                 char *uuid_str = GUID_string(call, transfer_syntax_uuid);
 574                 /* we only do NDR encoded dcerpc */
 575                 DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
 576                 talloc_free(uuid_str);
 577                 return dcesrv_bind_nak(call, 0);
 578         }
 579 
 580         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
 581         if (iface == NULL) {
 582                 char *uuid_str = GUID_string(call, &uuid);
 583                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
 584                 talloc_free(uuid_str);
 585 
 586                 /* we don't know about that interface */
 587                 result = DCERPC_BIND_PROVIDER_REJECT;
 588                 reason = DCERPC_BIND_REASON_ASYNTAX;            
 589         }
 590 
 591         if (iface) {
 592                 /* add this context to the list of available context_ids */
 593                 struct dcesrv_connection_context *context = talloc(call->conn, 
 594                                                                    struct dcesrv_connection_context);
 595                 if (context == NULL) {
 596                         return dcesrv_bind_nak(call, 0);
 597                 }
 598                 context->conn = call->conn;
 599                 context->iface = iface;
 600                 context->context_id = context_id;
 601                 /*
 602                  * we need to send a non zero assoc_group_id here to make longhorn happy,
 603                  * it also matches samba3
 604                  */
 605                 context->assoc_group_id = SAMBA_ASSOC_GROUP;
 606                 context->private_data = NULL;
 607                 context->handles = NULL;
 608                 DLIST_ADD(call->conn->contexts, context);
 609                 call->context = context;
 610                 talloc_set_destructor(context, dcesrv_connection_context_destructor);
 611 
 612                 status = iface->bind(call, iface);
 613                 if (!NT_STATUS_IS_OK(status)) {
 614                         char *uuid_str = GUID_string(call, &uuid);
 615                         DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n",
 616                                  uuid_str, if_version, nt_errstr(status)));
 617                         talloc_free(uuid_str);
 618                         /* we don't want to trigger the iface->unbind() hook */
 619                         context->iface = NULL;
 620                         talloc_free(call->context);
 621                         call->context = NULL;
 622                         return dcesrv_bind_nak(call, 0);
 623                 }
 624         }
 625 
 626         if (call->conn->cli_max_recv_frag == 0) {
 627                 call->conn->cli_max_recv_frag = call->pkt.u.bind.max_recv_frag;
 628         }
 629 
 630         if ((call->pkt.pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) &&
 631             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","header signing", false)) {
 632                 call->conn->state_flags |= DCESRV_CALL_STATE_FLAG_HEADER_SIGNING;
 633                 extra_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
 634         }
 635 
 636         /* handle any authentication that is being requested */
 637         if (!dcesrv_auth_bind(call)) {
 638                 talloc_free(call->context);
 639                 call->context = NULL;
 640                 return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
 641         }
 642 
 643         /* setup a bind_ack */
 644         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 645         pkt.auth_length = 0;
 646         pkt.call_id = call->pkt.call_id;
 647         pkt.ptype = DCERPC_PKT_BIND_ACK;
 648         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
 649         pkt.u.bind_ack.max_xmit_frag = 0x2000;
 650         pkt.u.bind_ack.max_recv_frag = 0x2000;
 651 
 652         /*
 653           make it possible for iface->bind() to specify the assoc_group_id
 654           This helps the openchange mapiproxy plugin to work correctly.
 655           
 656           metze
 657         */
 658         if (call->context) {
 659                 pkt.u.bind_ack.assoc_group_id = call->context->assoc_group_id;
 660         } else {
 661                 /* we better pick something - this chosen so as to send a non zero assoc_group_id (matching windows), it also matches samba3 */
 662                 pkt.u.bind_ack.assoc_group_id = SAMBA_ASSOC_GROUP;
 663         }
 664 
 665         if (iface) {
 666                 /* FIXME: Use pipe name as specified by endpoint instead of interface name */
 667                 pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
 668         } else {
 669                 pkt.u.bind_ack.secondary_address = "";
 670         }
 671         pkt.u.bind_ack.num_results = 1;
 672         pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
 673         if (!pkt.u.bind_ack.ctx_list) {
 674                 talloc_free(call->context);
 675                 call->context = NULL;
 676                 return NT_STATUS_NO_MEMORY;
 677         }
 678         pkt.u.bind_ack.ctx_list[0].result = result;
 679         pkt.u.bind_ack.ctx_list[0].reason = reason;
 680         pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
 681         pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
 682 
 683         status = dcesrv_auth_bind_ack(call, &pkt);
 684         if (!NT_STATUS_IS_OK(status)) {
 685                 talloc_free(call->context);
 686                 call->context = NULL;
 687                 return dcesrv_bind_nak(call, 0);
 688         }
 689 
 690         rep = talloc(call, struct data_blob_list_item);
 691         if (!rep) {
 692                 talloc_free(call->context);
 693                 call->context = NULL;
 694                 return NT_STATUS_NO_MEMORY;
 695         }
 696 
 697         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
 698         if (!NT_STATUS_IS_OK(status)) {
 699                 talloc_free(call->context);
 700                 call->context = NULL;
 701                 return status;
 702         }
 703 
 704         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 705 
 706         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 707         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 708 
 709         return NT_STATUS_OK;
 710 }
 711 
 712 
 713 /*
 714   handle a auth3 request
 715 */
 716 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
     /* [<][>][^][v][top][bottom][index][help] */
 717 {
 718         /* handle the auth3 in the auth code */
 719         if (!dcesrv_auth_auth3(call)) {
 720                 return dcesrv_fault(call, DCERPC_FAULT_OTHER);
 721         }
 722 
 723         talloc_free(call);
 724 
 725         /* we don't send a reply to a auth3 request, except by a
 726            fault */
 727         return NT_STATUS_OK;
 728 }
 729 
 730 
 731 /*
 732   handle a bind request
 733 */
 734 static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
     /* [<][>][^][v][top][bottom][index][help] */
 735 {
 736         uint32_t if_version, transfer_syntax_version;
 737         struct dcesrv_connection_context *context;
 738         const struct dcesrv_interface *iface;
 739         struct GUID uuid, *transfer_syntax_uuid;
 740         NTSTATUS status;
 741 
 742         if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
 743         uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
 744 
 745         transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
 746         transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
 747         if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
 748             ndr_transfer_syntax.if_version != transfer_syntax_version) {
 749                 /* we only do NDR encoded dcerpc */
 750                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
 751         }
 752 
 753         iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
 754         if (iface == NULL) {
 755                 char *uuid_str = GUID_string(call, &uuid);
 756                 DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
 757                 talloc_free(uuid_str);
 758                 return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
 759         }
 760 
 761         /* add this context to the list of available context_ids */
 762         context = talloc(call->conn, struct dcesrv_connection_context);
 763         if (context == NULL) {
 764                 return NT_STATUS_NO_MEMORY;
 765         }
 766         context->conn = call->conn;
 767         context->iface = iface;
 768         context->context_id = context_id;
 769         context->assoc_group_id = SAMBA_ASSOC_GROUP;
 770         context->private_data = NULL;
 771         context->handles = NULL;
 772         DLIST_ADD(call->conn->contexts, context);
 773         call->context = context;
 774         talloc_set_destructor(context, dcesrv_connection_context_destructor);
 775 
 776         status = iface->bind(call, iface);
 777         if (!NT_STATUS_IS_OK(status)) {
 778                 /* we don't want to trigger the iface->unbind() hook */
 779                 context->iface = NULL;
 780                 talloc_free(context);
 781                 call->context = NULL;
 782                 return status;
 783         }
 784 
 785         return NT_STATUS_OK;
 786 }
 787 
 788 
 789 /*
 790   handle a alter context request
 791 */
 792 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
     /* [<][>][^][v][top][bottom][index][help] */
 793 {
 794         struct ncacn_packet pkt;
 795         struct data_blob_list_item *rep;
 796         NTSTATUS status;
 797         uint32_t result=0, reason=0;
 798         uint32_t context_id;
 799 
 800         /* handle any authentication that is being requested */
 801         if (!dcesrv_auth_alter(call)) {
 802                 /* TODO: work out the right reject code */
 803                 result = DCERPC_BIND_PROVIDER_REJECT;
 804                 reason = DCERPC_BIND_REASON_ASYNTAX;            
 805         }
 806 
 807         context_id = call->pkt.u.alter.ctx_list[0].context_id;
 808 
 809         /* see if they are asking for a new interface */
 810         if (result == 0) {
 811                 call->context = dcesrv_find_context(call->conn, context_id);
 812                 if (!call->context) {
 813                         status = dcesrv_alter_new_context(call, context_id);
 814                         if (!NT_STATUS_IS_OK(status)) {
 815                                 result = DCERPC_BIND_PROVIDER_REJECT;
 816                                 reason = DCERPC_BIND_REASON_ASYNTAX;
 817                         }
 818                 }
 819         }
 820 
 821         if (result == 0 &&
 822             call->pkt.u.alter.assoc_group_id != 0 &&
 823             lp_parm_bool(call->conn->dce_ctx->lp_ctx, NULL, "dcesrv","assoc group checking", true) &&
 824             call->pkt.u.alter.assoc_group_id != call->context->assoc_group_id) {
 825                 /* TODO: work out what to return here */
 826                 result = DCERPC_BIND_PROVIDER_REJECT;
 827                 reason = DCERPC_BIND_REASON_ASYNTAX;
 828         }
 829 
 830         /* setup a alter_resp */
 831         dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
 832         pkt.auth_length = 0;
 833         pkt.call_id = call->pkt.call_id;
 834         pkt.ptype = DCERPC_PKT_ALTER_RESP;
 835         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
 836         pkt.u.alter_resp.max_xmit_frag = 0x2000;
 837         pkt.u.alter_resp.max_recv_frag = 0x2000;
 838         if (result == 0) {
 839                 pkt.u.alter_resp.assoc_group_id = call->context->assoc_group_id;
 840         } else {
 841                 pkt.u.alter_resp.assoc_group_id = 0;
 842         }
 843         pkt.u.alter_resp.num_results = 1;
 844         pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
 845         if (!pkt.u.alter_resp.ctx_list) {
 846                 return NT_STATUS_NO_MEMORY;
 847         }
 848         pkt.u.alter_resp.ctx_list[0].result = result;
 849         pkt.u.alter_resp.ctx_list[0].reason = reason;
 850         pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
 851         pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
 852         pkt.u.alter_resp.secondary_address = "";
 853 
 854         status = dcesrv_auth_alter_ack(call, &pkt);
 855         if (!NT_STATUS_IS_OK(status)) {
 856                 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
 857                     || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
 858                     || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
 859                     || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
 860                         return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
 861                 }
 862                 return dcesrv_fault(call, 0);
 863         }
 864 
 865         rep = talloc(call, struct data_blob_list_item);
 866         if (!rep) {
 867                 return NT_STATUS_NO_MEMORY;
 868         }
 869 
 870         status = ncacn_push_auth(&rep->blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx), &pkt, call->conn->auth_state.auth_info);
 871         if (!NT_STATUS_IS_OK(status)) {
 872                 return status;
 873         }
 874 
 875         dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 876 
 877         DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
 878         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 879 
 880         return NT_STATUS_OK;
 881 }
 882 
 883 /*
 884   handle a dcerpc request packet
 885 */
 886 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
     /* [<][>][^][v][top][bottom][index][help] */
 887 {
 888         struct ndr_pull *pull;
 889         NTSTATUS status;
 890         struct dcesrv_connection_context *context;
 891 
 892         /* if authenticated, and the mech we use can't do async replies, don't use them... */
 893         if (call->conn->auth_state.gensec_security && 
 894             !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
 895                 call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
 896         }
 897 
 898         context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
 899         if (context == NULL) {
 900                 return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
 901         }
 902 
 903         pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call,
 904                                   lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
 905         NT_STATUS_HAVE_NO_MEMORY(pull);
 906 
 907         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
 908 
 909         call->context   = context;
 910         call->ndr_pull  = pull;
 911 
 912         if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
 913                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
 914         }
 915 
 916         /* unravel the NDR for the packet */
 917         status = context->iface->ndr_pull(call, call, pull, &call->r);
 918         if (!NT_STATUS_IS_OK(status)) {
 919                 return dcesrv_fault(call, call->fault_code);
 920         }
 921 
 922         if (pull->offset != pull->data_size) {
 923                 DEBUG(3,("Warning: %d extra bytes in incoming RPC request\n", 
 924                          pull->data_size - pull->offset));
 925                 dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
 926         }
 927 
 928         /* call the dispatch function */
 929         status = context->iface->dispatch(call, call, call->r);
 930         if (!NT_STATUS_IS_OK(status)) {
 931                 DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
 932                          context->iface->name, 
 933                          call->pkt.u.request.opnum,
 934                          dcerpc_errstr(pull, call->fault_code)));
 935                 return dcesrv_fault(call, call->fault_code);
 936         }
 937 
 938         /* add the call to the pending list */
 939         dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
 940 
 941         if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
 942                 return NT_STATUS_OK;
 943         }
 944 
 945         return dcesrv_reply(call);
 946 }
 947 
 948 _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
     /* [<][>][^][v][top][bottom][index][help] */
 949 {
 950         struct ndr_push *push;
 951         NTSTATUS status;
 952         DATA_BLOB stub;
 953         uint32_t total_length, chunk_size;
 954         struct dcesrv_connection_context *context = call->context;
 955         size_t sig_size = 0;
 956 
 957         /* call the reply function */
 958         status = context->iface->reply(call, call, call->r);
 959         if (!NT_STATUS_IS_OK(status)) {
 960                 return dcesrv_fault(call, call->fault_code);
 961         }
 962 
 963         /* form the reply NDR */
 964         push = ndr_push_init_ctx(call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
 965         NT_STATUS_HAVE_NO_MEMORY(push);
 966 
 967         /* carry over the pointer count to the reply in case we are
 968            using full pointer. See NDR specification for full
 969            pointers */
 970         push->ptr_count = call->ndr_pull->ptr_count;
 971 
 972         if (lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx)) {
 973                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
 974         }
 975 
 976         status = context->iface->ndr_push(call, call, push, call->r);
 977         if (!NT_STATUS_IS_OK(status)) {
 978                 return dcesrv_fault(call, call->fault_code);
 979         }
 980 
 981         stub = ndr_push_blob(push);
 982 
 983         total_length = stub.length;
 984 
 985         /* we can write a full max_recv_frag size, minus the dcerpc
 986            request header size */
 987         chunk_size = call->conn->cli_max_recv_frag;
 988         chunk_size -= DCERPC_REQUEST_LENGTH;
 989         if (call->conn->auth_state.auth_info &&
 990             call->conn->auth_state.gensec_security) {
 991                 sig_size = gensec_sig_size(call->conn->auth_state.gensec_security,
 992                                            call->conn->cli_max_recv_frag);
 993                 if (sig_size) {
 994                         chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
 995                         chunk_size -= sig_size;
 996                 }
 997         }
 998         chunk_size -= (chunk_size % 16);
 999 
1000         do {
1001                 uint32_t length;
1002                 struct data_blob_list_item *rep;
1003                 struct ncacn_packet pkt;
1004 
1005                 rep = talloc(call, struct data_blob_list_item);
1006                 NT_STATUS_HAVE_NO_MEMORY(rep);
1007 
1008                 length = MIN(chunk_size, stub.length);
1009 
1010                 /* form the dcerpc response packet */
1011                 dcesrv_init_hdr(&pkt, lp_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
1012                 pkt.auth_length = 0;
1013                 pkt.call_id = call->pkt.call_id;
1014                 pkt.ptype = DCERPC_PKT_RESPONSE;
1015                 pkt.pfc_flags = 0;
1016                 if (stub.length == total_length) {
1017                         pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1018                 }
1019                 if (length == stub.length) {
1020                         pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1021                 }
1022                 pkt.u.response.alloc_hint = stub.length;
1023                 pkt.u.response.context_id = call->pkt.u.request.context_id;
1024                 pkt.u.response.cancel_count = 0;
1025                 pkt.u.response.stub_and_verifier.data = stub.data;
1026                 pkt.u.response.stub_and_verifier.length = length;
1027 
1028                 if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) {
1029                         return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
1030                 }
1031 
1032                 dcerpc_set_frag_length(&rep->blob, rep->blob.length);
1033 
1034                 DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
1035                 
1036                 stub.data += length;
1037                 stub.length -= length;
1038         } while (stub.length != 0);
1039 
1040         /* move the call from the pending to the finished calls list */
1041         dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
1042 
1043         if (call->conn->call_list && call->conn->call_list->replies) {
1044                 if (call->conn->transport.report_output_data) {
1045                         call->conn->transport.report_output_data(call->conn);
1046                 }
1047         }
1048 
1049         return NT_STATUS_OK;
1050 }
1051 
1052 _PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1053 {
1054         if (!conn->transport.get_my_addr) {
1055                 return NULL;
1056         }
1057 
1058         return conn->transport.get_my_addr(conn, mem_ctx);
1059 }
1060 
1061 _PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1062 {
1063         if (!conn->transport.get_peer_addr) {
1064                 return NULL;
1065         }
1066 
1067         return conn->transport.get_peer_addr(conn, mem_ctx);
1068 }
1069 
1070 /*
1071   work out if we have a full packet yet
1072 */
1073 static bool dce_full_packet(const DATA_BLOB *data)
     /* [<][>][^][v][top][bottom][index][help] */
1074 {
1075         if (data->length < DCERPC_FRAG_LEN_OFFSET+2) {
1076                 return false;
1077         }
1078         if (dcerpc_get_frag_length(data) > data->length) {
1079                 return false;
1080         }
1081         return true;
1082 }
1083 
1084 /*
1085   we might have consumed only part of our input - advance past that part
1086 */
1087 static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t offset)
     /* [<][>][^][v][top][bottom][index][help] */
1088 {
1089         DATA_BLOB blob;
1090 
1091         if (dce_conn->partial_input.length == offset) {
1092                 data_blob_free(&dce_conn->partial_input);
1093                 return;
1094         }
1095 
1096         blob = dce_conn->partial_input;
1097         dce_conn->partial_input = data_blob(blob.data + offset,
1098                                             blob.length - offset);
1099         data_blob_free(&blob);
1100 }
1101 
1102 /*
1103   remove the call from the right list when freed
1104  */
1105 static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
     /* [<][>][^][v][top][bottom][index][help] */
1106 {
1107         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1108         return 0;
1109 }
1110 
1111 /*
1112   process some input to a dcerpc endpoint server.
1113 */
1114 NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
     /* [<][>][^][v][top][bottom][index][help] */
1115 {
1116         struct ndr_pull *ndr;
1117         enum ndr_err_code ndr_err;
1118         NTSTATUS status;
1119         struct dcesrv_call_state *call;
1120         DATA_BLOB blob;
1121 
1122         call = talloc_zero(dce_conn, struct dcesrv_call_state);
1123         if (!call) {
1124                 talloc_free(dce_conn->partial_input.data);
1125                 return NT_STATUS_NO_MEMORY;
1126         }
1127         call->conn              = dce_conn;
1128         call->event_ctx         = dce_conn->event_ctx;
1129         call->msg_ctx           = dce_conn->msg_ctx;
1130         call->state_flags       = call->conn->state_flags;
1131         call->time              = timeval_current();
1132         call->list              = DCESRV_LIST_NONE;
1133 
1134         talloc_set_destructor(call, dcesrv_call_dequeue);
1135 
1136         blob = dce_conn->partial_input;
1137         blob.length = dcerpc_get_frag_length(&blob);
1138 
1139         ndr = ndr_pull_init_blob(&blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
1140         if (!ndr) {
1141                 talloc_free(dce_conn->partial_input.data);
1142                 talloc_free(call);
1143                 return NT_STATUS_NO_MEMORY;
1144         }
1145 
1146         if (!(CVAL(blob.data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
1147                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
1148         }
1149 
1150         if (CVAL(blob.data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
1151                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
1152         }
1153 
1154         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
1155         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1156                 talloc_free(dce_conn->partial_input.data);
1157                 talloc_free(call);
1158                 return ndr_map_error2ntstatus(ndr_err);
1159         }
1160 
1161         /* we have to check the signing here, before combining the
1162            pdus */
1163         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1164             !dcesrv_auth_request(call, &blob)) {
1165                 dce_partial_advance(dce_conn, blob.length);
1166                 return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
1167         }
1168 
1169         dce_partial_advance(dce_conn, blob.length);
1170 
1171         /* see if this is a continued packet */
1172         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1173             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
1174                 struct dcesrv_call_state *call2 = call;
1175                 uint32_t alloc_size;
1176 
1177                 /* we only allow fragmented requests, no other packet types */
1178                 if (call->pkt.ptype != DCERPC_PKT_REQUEST) {
1179                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1180                 }
1181 
1182                 /* this is a continuation of an existing call - find the call then
1183                    tack it on the end */
1184                 call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
1185                 if (!call) {
1186                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1187                 }
1188 
1189                 if (call->pkt.ptype != call2->pkt.ptype) {
1190                         /* trying to play silly buggers are we? */
1191                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1192                 }
1193 
1194                 alloc_size = call->pkt.u.request.stub_and_verifier.length +
1195                         call2->pkt.u.request.stub_and_verifier.length;
1196                 if (call->pkt.u.request.alloc_hint > alloc_size) {
1197                         alloc_size = call->pkt.u.request.alloc_hint;
1198                 }
1199 
1200                 call->pkt.u.request.stub_and_verifier.data = 
1201                         talloc_realloc(call, 
1202                                        call->pkt.u.request.stub_and_verifier.data, 
1203                                        uint8_t, alloc_size);
1204                 if (!call->pkt.u.request.stub_and_verifier.data) {
1205                         return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
1206                 }
1207                 memcpy(call->pkt.u.request.stub_and_verifier.data +
1208                        call->pkt.u.request.stub_and_verifier.length,
1209                        call2->pkt.u.request.stub_and_verifier.data,
1210                        call2->pkt.u.request.stub_and_verifier.length);
1211                 call->pkt.u.request.stub_and_verifier.length += 
1212                         call2->pkt.u.request.stub_and_verifier.length;
1213 
1214                 call->pkt.pfc_flags |= (call2->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST);
1215 
1216                 talloc_free(call2);
1217         }
1218 
1219         /* this may not be the last pdu in the chain - if its isn't then
1220            just put it on the incoming_fragmented_call_list and wait for the rest */
1221         if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
1222             !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1223                 dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
1224                 return NT_STATUS_OK;
1225         } 
1226         
1227         /* This removes any fragments we may have had stashed away */
1228         dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1229 
1230         switch (call->pkt.ptype) {
1231         case DCERPC_PKT_BIND:
1232                 status = dcesrv_bind(call);
1233                 break;
1234         case DCERPC_PKT_AUTH3:
1235                 status = dcesrv_auth3(call);
1236                 break;
1237         case DCERPC_PKT_ALTER:
1238                 status = dcesrv_alter(call);
1239                 break;
1240         case DCERPC_PKT_REQUEST:
1241                 status = dcesrv_request(call);
1242                 break;
1243         default:
1244                 status = NT_STATUS_INVALID_PARAMETER;
1245                 break;
1246         }
1247 
1248         /* if we are going to be sending a reply then add
1249            it to the list of pending calls. We add it to the end to keep the call
1250            list in the order we will answer */
1251         if (!NT_STATUS_IS_OK(status)) {
1252                 talloc_free(call);
1253         }
1254 
1255         return status;
1256 }
1257 
1258 
1259 /*
1260   provide some input to a dcerpc endpoint server. This passes data
1261   from a dcerpc client into the server
1262 */
1263 _PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
     /* [<][>][^][v][top][bottom][index][help] */
1264 {
1265         NTSTATUS status;
1266 
1267         dce_conn->partial_input.data = talloc_realloc(dce_conn,
1268                                                       dce_conn->partial_input.data,
1269                                                       uint8_t,
1270                                                       dce_conn->partial_input.length + data->length);
1271         if (!dce_conn->partial_input.data) {
1272                 return NT_STATUS_NO_MEMORY;
1273         }
1274         memcpy(dce_conn->partial_input.data + dce_conn->partial_input.length,
1275                data->data, data->length);
1276         dce_conn->partial_input.length += data->length;
1277 
1278         while (dce_full_packet(&dce_conn->partial_input)) {
1279                 status = dcesrv_input_process(dce_conn);
1280                 if (!NT_STATUS_IS_OK(status)) {
1281                         return status;
1282                 }
1283         }
1284 
1285         return NT_STATUS_OK;
1286 }
1287 
1288 /*
1289   retrieve some output from a dcerpc server
1290   The caller supplies a function that will be called to do the
1291   actual output. 
1292 
1293   The first argument to write_fn() will be 'private', the second will
1294   be a pointer to a buffer containing the data to be sent and the 3rd
1295   will be a pointer to a size_t variable that will be set to the
1296   number of bytes that are consumed from the output.
1297 
1298   from the current fragment
1299 */
1300 _PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
     /* [<][>][^][v][top][bottom][index][help] */
1301                        void *private_data,
1302                        NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
1303 {
1304         NTSTATUS status;
1305         struct dcesrv_call_state *call;
1306         struct data_blob_list_item *rep;
1307         size_t nwritten;
1308 
1309         call = dce_conn->call_list;
1310         if (!call || !call->replies) {
1311                 if (dce_conn->pending_call_list) {
1312                         /* TODO: we need to say act async here
1313                          *       as we know we have pending requests
1314                          *       which will be finished at a time
1315                          */
1316                         return NT_STATUS_FOOBAR;
1317                 }
1318                 return NT_STATUS_FOOBAR;
1319         }
1320         rep = call->replies;
1321 
1322         status = write_fn(private_data, &rep->blob, &nwritten);
1323         NT_STATUS_IS_ERR_RETURN(status);
1324 
1325         rep->blob.length -= nwritten;
1326         rep->blob.data += nwritten;
1327 
1328         if (rep->blob.length == 0) {
1329                 /* we're done with this section of the call */
1330                 DLIST_REMOVE(call->replies, rep);
1331         }
1332 
1333         if (call->replies == NULL) {
1334                 /* we're done with the whole call */
1335                 dcesrv_call_set_list(call, DCESRV_LIST_NONE);
1336                 talloc_free(call);
1337         }
1338 
1339         return status;
1340 }
1341 
1342 _PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
1343                                       struct loadparm_context *lp_ctx,
1344                                       const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
1345 {
1346         NTSTATUS status;
1347         struct dcesrv_context *dce_ctx;
1348         int i;
1349 
1350         if (!endpoint_servers) {
1351                 DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
1352                 return NT_STATUS_INTERNAL_ERROR;
1353         }
1354 
1355         dce_ctx = talloc(mem_ctx, struct dcesrv_context);
1356         NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
1357         dce_ctx->endpoint_list  = NULL;
1358         dce_ctx->lp_ctx = lp_ctx;
1359 
1360         for (i=0;endpoint_servers[i];i++) {
1361                 const struct dcesrv_endpoint_server *ep_server;
1362 
1363                 ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
1364                 if (!ep_server) {
1365                         DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
1366                         return NT_STATUS_INTERNAL_ERROR;
1367                 }
1368 
1369                 status = ep_server->init_server(dce_ctx, ep_server);
1370                 if (!NT_STATUS_IS_OK(status)) {
1371                         DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
1372                                 nt_errstr(status)));
1373                         return status;
1374                 }
1375         }
1376 
1377         *_dce_ctx = dce_ctx;
1378         return NT_STATUS_OK;
1379 }
1380 
1381 /* the list of currently registered DCERPC endpoint servers.
1382  */
1383 static struct ep_server {
1384         struct dcesrv_endpoint_server *ep_server;
1385 } *ep_servers = NULL;
1386 static int num_ep_servers;
1387 
1388 /*
1389   register a DCERPC endpoint server. 
1390 
1391   The 'name' can be later used by other backends to find the operations
1392   structure for this backend.  
1393 
1394   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
1395 */
1396 _PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
     /* [<][>][^][v][top][bottom][index][help] */
1397 {
1398         const struct dcesrv_endpoint_server *ep_server = _ep_server;
1399         
1400         if (dcesrv_ep_server_byname(ep_server->name) != NULL) {
1401                 /* its already registered! */
1402                 DEBUG(0,("DCERPC endpoint server '%s' already registered\n", 
1403                          ep_server->name));
1404                 return NT_STATUS_OBJECT_NAME_COLLISION;
1405         }
1406 
1407         ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
1408         if (!ep_servers) {
1409                 smb_panic("out of memory in dcerpc_register");
1410         }
1411 
1412         ep_servers[num_ep_servers].ep_server = smb_xmemdup(ep_server, sizeof(*ep_server));
1413         ep_servers[num_ep_servers].ep_server->name = smb_xstrdup(ep_server->name);
1414 
1415         num_ep_servers++;
1416 
1417         DEBUG(3,("DCERPC endpoint server '%s' registered\n", 
1418                  ep_server->name));
1419 
1420         return NT_STATUS_OK;
1421 }
1422 
1423 /*
1424   return the operations structure for a named backend of the specified type
1425 */
1426 const struct dcesrv_endpoint_server *dcesrv_ep_server_byname(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
1427 {
1428         int i;
1429 
1430         for (i=0;i<num_ep_servers;i++) {
1431                 if (strcmp(ep_servers[i].ep_server->name, name) == 0) {
1432                         return ep_servers[i].ep_server;
1433                 }
1434         }
1435 
1436         return NULL;
1437 }
1438 
1439 void dcerpc_server_init(struct loadparm_context *lp_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1440 {
1441         static bool initialized;
1442         extern NTSTATUS dcerpc_server_wkssvc_init(void);
1443         extern NTSTATUS dcerpc_server_drsuapi_init(void);
1444         extern NTSTATUS dcerpc_server_winreg_init(void);
1445         extern NTSTATUS dcerpc_server_spoolss_init(void);
1446         extern NTSTATUS dcerpc_server_epmapper_init(void);
1447         extern NTSTATUS dcerpc_server_srvsvc_init(void);
1448         extern NTSTATUS dcerpc_server_netlogon_init(void);
1449         extern NTSTATUS dcerpc_server_rpcecho_init(void);
1450         extern NTSTATUS dcerpc_server_unixinfo_init(void);
1451         extern NTSTATUS dcerpc_server_samr_init(void);
1452         extern NTSTATUS dcerpc_server_remote_init(void);
1453         extern NTSTATUS dcerpc_server_lsa_init(void);
1454         extern NTSTATUS dcerpc_server_browser_init(void);
1455         init_module_fn static_init[] = { STATIC_dcerpc_server_MODULES };
1456         init_module_fn *shared_init;
1457 
1458         if (initialized) {
1459                 return;
1460         }
1461         initialized = true;
1462 
1463         shared_init = load_samba_modules(NULL, lp_ctx, "dcerpc_server");
1464 
1465         run_init_functions(static_init);
1466         run_init_functions(shared_init);
1467 
1468         talloc_free(shared_init);
1469 }
1470 
1471 /*
1472   return the DCERPC module version, and the size of some critical types
1473   This can be used by endpoint server modules to either detect compilation errors, or provide
1474   multiple implementations for different smbd compilation options in one module
1475 */
1476 const struct dcesrv_critical_sizes *dcerpc_module_version(void)
     /* [<][>][^][v][top][bottom][index][help] */
1477 {
1478         static const struct dcesrv_critical_sizes critical_sizes = {
1479                 DCERPC_MODULE_VERSION,
1480                 sizeof(struct dcesrv_context),
1481                 sizeof(struct dcesrv_endpoint),
1482                 sizeof(struct dcesrv_endpoint_server),
1483                 sizeof(struct dcesrv_interface),
1484                 sizeof(struct dcesrv_if_list),
1485                 sizeof(struct dcesrv_connection),
1486                 sizeof(struct dcesrv_call_state),
1487                 sizeof(struct dcesrv_auth),
1488                 sizeof(struct dcesrv_handle)
1489         };
1490 
1491         return &critical_sizes;
1492 }
1493 
1494 /*
1495   initialise the dcerpc server context for ncacn_np based services
1496 */
1497 _PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1498                                           struct dcesrv_context **_dce_ctx)
1499 {
1500         NTSTATUS status;
1501         struct dcesrv_context *dce_ctx;
1502 
1503         dcerpc_server_init(lp_ctx);
1504 
1505         status = dcesrv_init_context(mem_ctx, lp_ctx, lp_dcerpc_endpoint_servers(lp_ctx), &dce_ctx);
1506         NT_STATUS_NOT_OK_RETURN(status);
1507 
1508         *_dce_ctx = dce_ctx;
1509         return NT_STATUS_OK;
1510 }
1511 
1512 

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