r25026: Move param/param.h out of includes.h
[kai/samba.git] / source4 / rpc_server / dcerpc_server.c
index 925004b191ab06ee303e4daa41c9e5ed2f589360..c3de00d8d0c87135062b0cb5cc6eac14285babab 100644 (file)
@@ -3,12 +3,12 @@
 
    server side dcerpc core code
 
-   Copyright (C) Andrew Tridgell 2003
-   Copyright (C) Stefan (metze) Metzmacher 2004
+   Copyright (C) Andrew Tridgell 2003-2005
+   Copyright (C) Stefan (metze) Metzmacher 2004-2005
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "librpc/gen_ndr/ndr_epmapper.h"
-#include "librpc/gen_ndr/ndr_oxidresolver.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
 #include "auth/auth.h"
-#include "dlinklist.h"
+#include "auth/gensec/gensec.h"
+#include "lib/util/dlinklist.h"
 #include "rpc_server/dcerpc_server.h"
+#include "lib/events/events.h"
+#include "smbd/service_task.h"
+#include "smbd/service_stream.h"
+#include "smbd/service.h"
+#include "system/filesys.h"
+#include "libcli/security/security.h"
+#include "build.h"
+#include "param/param.h"
+
+extern const struct dcesrv_interface dcesrv_mgmt_interface;
 
 /*
   see if two endpoints match
 */
-static BOOL endpoints_match(const struct dcerpc_binding *ep1,
+static bool endpoints_match(const struct dcerpc_binding *ep1,
                            const struct dcerpc_binding *ep2)
 {
        if (ep1->transport != ep2->transport) {
-               return False;
+               return false;
        }
 
        if (!ep1->endpoint || !ep2->endpoint) {
@@ -43,9 +52,9 @@ static BOOL endpoints_match(const struct dcerpc_binding *ep1,
        }
 
        if (strcasecmp(ep1->endpoint, ep2->endpoint) != 0) 
-               return False;
+               return false;
 
-       return True;
+       return true;
 }
 
 /*
@@ -56,7 +65,7 @@ static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
 {
        struct dcesrv_endpoint *ep;
        for (ep=dce_ctx->endpoint_list; ep; ep=ep->next) {
-               if (endpoints_match(&ep->ep_description, ep_description)) {
+               if (endpoints_match(ep->ep_description, ep_description)) {
                        return ep;
                }
        }
@@ -82,15 +91,8 @@ static struct dcesrv_connection_context *dcesrv_find_context(struct dcesrv_conne
 static BOOL interface_match(const struct dcesrv_interface *if1,
                                                        const struct dcesrv_interface *if2)
 {
-       if (if1->if_version != if2->if_version) {
-               return False;
-       }
-
-       if (strcmp(if1->uuid, if2->uuid)==0) {
-               return True;
-       }                       
-
-       return False;
+       return (if1->syntax_id.if_version == if2->syntax_id.if_version && 
+                       GUID_equal(&if1->syntax_id.uuid, &if2->syntax_id.uuid));
 }
 
 /*
@@ -112,24 +114,17 @@ static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoin
   see if a uuid and if_version match to an interface
 */
 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
-                                   const char *uuid, uint32_t if_version)
+                                   const struct GUID *uuid, uint32_t if_version)
 {
-       if (iface->if_version != if_version) {
-               return False;
-       }
-
-       if (strcmp(iface->uuid, uuid)==0) {
-               return True;
-       }                       
-
-       return False;
+       return (iface->syntax_id.if_version == if_version && 
+                       GUID_equal(&iface->syntax_id.uuid, uuid));
 }
 
 /*
   find the interface operations on an endpoint by uuid
 */
 static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv_endpoint *endpoint,
-                                                            const char *uuid, uint32_t if_version)
+                                                            const struct GUID *uuid, uint32_t if_version)
 {
        struct dcesrv_if_list *ifl;
        for (ifl=endpoint->interface_list; ifl; ifl=ifl->next) {
@@ -141,12 +136,12 @@ static const struct dcesrv_interface *find_interface_by_uuid(const struct dcesrv
 }
 
 /*
-  find a call that is pending in our call list
+  find the earlier parts of a fragmented call awaiting reassembily
 */
-static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
+static struct dcesrv_call_state *dcesrv_find_fragmented_call(struct dcesrv_connection *dce_conn, uint16_t call_id)
 {
        struct dcesrv_call_state *c;
-       for (c=dce_conn->call_list;c;c=c->next) {
+       for (c=dce_conn->incoming_fragmented_call_list;c;c=c->next) {
                if (c->pkt.call_id == call_id) {
                        return c;
                }
@@ -157,14 +152,14 @@ static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_
 /*
   register an interface on an endpoint
 */
-NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
+_PUBLIC_ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
                                   const char *ep_name,
                                   const struct dcesrv_interface *iface,
                                   const struct security_descriptor *sd)
 {
        struct dcesrv_endpoint *ep;
        struct dcesrv_if_list *ifl;
-       struct dcerpc_binding binding;
+       struct dcerpc_binding *binding;
        BOOL add_ep = False;
        NTSTATUS status;
        
@@ -177,14 +172,25 @@ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
 
        /* check if this endpoint exists
         */
-       if ((ep=find_endpoint(dce_ctx, &binding))==NULL) {
-               ep = talloc_p(dce_ctx, struct dcesrv_endpoint);
+       if ((ep=find_endpoint(dce_ctx, binding))==NULL) {
+               ep = talloc(dce_ctx, struct dcesrv_endpoint);
                if (!ep) {
                        return NT_STATUS_NO_MEMORY;
                }
                ZERO_STRUCTP(ep);
-               ep->ep_description = binding;
+               ep->ep_description = talloc_reference(ep, binding);
                add_ep = True;
+
+               /* add mgmt interface */
+               ifl = talloc(dce_ctx, struct dcesrv_if_list);
+               if (!ifl) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               memcpy(&(ifl->iface), &dcesrv_mgmt_interface, 
+                          sizeof(struct dcesrv_interface));
+
+               DLIST_ADD(ep->interface_list, ifl);
        }
 
        /* see if the interface is already registered on te endpoint */
@@ -195,7 +201,7 @@ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
        }
 
        /* talloc a new interface list element */
-       ifl = talloc_p(dce_ctx, struct dcesrv_if_list);
+       ifl = talloc(dce_ctx, struct dcesrv_if_list);
        if (!ifl) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -264,7 +270,7 @@ NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
 /*
   fetch the user session key - may be default (above) or the SMB session key
 */
-NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
+_PUBLIC_ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
                                  DATA_BLOB *session_key)
 {
        return p->auth_state.session_key(p, session_key);
@@ -274,10 +280,8 @@ NTSTATUS dcesrv_fetch_session_key(struct dcesrv_connection *p,
 /*
   destroy a link to an endpoint
 */
-static int dcesrv_endpoint_destructor(void *ptr)
+static int dcesrv_endpoint_destructor(struct dcesrv_connection *p)
 {
-       struct dcesrv_connection *p = ptr;
-
        while (p->contexts) {
                struct dcesrv_connection_context *c = p->contexts;
 
@@ -286,10 +290,8 @@ static int dcesrv_endpoint_destructor(void *ptr)
                if (c->iface) {
                        c->iface->unbind(c, c->iface);
                }
-               talloc_free(c);
        }
 
-
        return 0;
 }
 
@@ -298,37 +300,65 @@ static int dcesrv_endpoint_destructor(void *ptr)
   connect to a dcerpc endpoint
 */
 NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
+                                TALLOC_CTX *mem_ctx,
                                 const struct dcesrv_endpoint *ep,
-                                struct dcesrv_connection **p)
+                                struct auth_session_info *session_info,
+                                struct event_context *event_ctx,
+                                struct messaging_context *msg_ctx,
+                                struct server_id server_id,
+                                uint32_t state_flags,
+                                struct dcesrv_connection **_p)
 {
-       *p = talloc_p(dce_ctx, struct dcesrv_connection);
-       if (! *p) {
-               return NT_STATUS_NO_MEMORY;
+       struct dcesrv_connection *p;
+
+       if (!session_info) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
-       (*p)->dce_ctx = dce_ctx;
-       (*p)->endpoint = ep;
-       (*p)->contexts = NULL;
-       (*p)->call_list = NULL;
-       (*p)->cli_max_recv_frag = 0;
-       (*p)->partial_input = data_blob(NULL, 0);
-       (*p)->auth_state.auth_info = NULL;
-       (*p)->auth_state.gensec_security = NULL;
-       (*p)->auth_state.session_info = NULL;
-       (*p)->auth_state.session_key = dcesrv_generic_session_key;
-       (*p)->srv_conn = NULL;
+       p = talloc(mem_ctx, struct dcesrv_connection);
+       NT_STATUS_HAVE_NO_MEMORY(p);
 
-       talloc_set_destructor(*p, dcesrv_endpoint_destructor);
+       if (!talloc_reference(p, session_info)) {
+               talloc_free(p);
+               return NT_STATUS_NO_MEMORY;
+       }
 
+       p->dce_ctx = dce_ctx;
+       p->endpoint = ep;
+       p->contexts = NULL;
+       p->call_list = NULL;
+       p->incoming_fragmented_call_list = NULL;
+       p->pending_call_list = NULL;
+       p->cli_max_recv_frag = 0;
+       p->partial_input = data_blob(NULL, 0);
+       p->auth_state.auth_info = NULL;
+       p->auth_state.gensec_security = NULL;
+       p->auth_state.session_info = session_info;
+       p->auth_state.session_key = dcesrv_generic_session_key;
+       p->event_ctx = event_ctx;
+       p->msg_ctx = msg_ctx;
+       p->server_id = server_id;
+       p->processing = False;
+       p->state_flags = state_flags;
+       ZERO_STRUCT(p->transport);
+
+       talloc_set_destructor(p, dcesrv_endpoint_destructor);
+
+       *_p = p;
        return NT_STATUS_OK;
 }
 
 /*
   search and connect to a dcerpc endpoint
 */
-NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
+_PUBLIC_ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
+                                       TALLOC_CTX *mem_ctx,
                                        const struct dcerpc_binding *ep_description,
                                        struct auth_session_info *session_info,
+                                       struct event_context *event_ctx,
+                                       struct messaging_context *msg_ctx,
+                                       struct server_id server_id,
+                                       uint32_t state_flags,
                                        struct dcesrv_connection **dce_conn_p)
 {
        NTSTATUS status;
@@ -340,12 +370,11 @@ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       status = dcesrv_endpoint_connect(dce_ctx, ep, dce_conn_p);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       status = dcesrv_endpoint_connect(dce_ctx, mem_ctx, ep, session_info,
+                                        event_ctx, msg_ctx, server_id,
+                                        state_flags, dce_conn_p);
+       NT_STATUS_NOT_OK_RETURN(status);
 
-       (*dce_conn_p)->auth_state.session_info = talloc_reference((*dce_conn_p), session_info);
        (*dce_conn_p)->auth_state.session_key = dcesrv_inherited_session_key;
 
        /* TODO: check security descriptor of the endpoint here 
@@ -357,7 +386,7 @@ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
 }
 
 
-static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
+static void dcesrv_init_hdr(struct ncacn_packet *pkt)
 {
        pkt->rpc_vers = 5;
        pkt->rpc_vers_minor = 0;
@@ -371,13 +400,50 @@ static void dcesrv_init_hdr(struct dcerpc_packet *pkt)
        pkt->drep[3] = 0;
 }
 
+/*
+  move a call from an existing linked list to the specified list. This
+  prevents bugs where we forget to remove the call from a previous
+  list when moving it.
+ */
+static void dcesrv_call_set_list(struct dcesrv_call_state *call, 
+                                enum dcesrv_call_list list)
+{
+       switch (call->list) {
+       case DCESRV_LIST_NONE:
+               break;
+       case DCESRV_LIST_CALL_LIST:
+               DLIST_REMOVE(call->conn->call_list, call);
+               break;
+       case DCESRV_LIST_FRAGMENTED_CALL_LIST:
+               DLIST_REMOVE(call->conn->incoming_fragmented_call_list, call);
+               break;
+       case DCESRV_LIST_PENDING_CALL_LIST:
+               DLIST_REMOVE(call->conn->pending_call_list, call);
+               break;
+       }
+       call->list = list;
+       switch (list) {
+       case DCESRV_LIST_NONE:
+               break;
+       case DCESRV_LIST_CALL_LIST:
+               DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+               break;
+       case DCESRV_LIST_FRAGMENTED_CALL_LIST:
+               DLIST_ADD_END(call->conn->incoming_fragmented_call_list, call, struct dcesrv_call_state *);
+               break;
+       case DCESRV_LIST_PENDING_CALL_LIST:
+               DLIST_ADD_END(call->conn->pending_call_list, call, struct dcesrv_call_state *);
+               break;
+       }
+}
+
 /*
   return a dcerpc fault
 */
 static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code)
 {
-       struct dcerpc_packet pkt;
-       struct dcesrv_call_reply *rep;
+       struct ncacn_packet pkt;
+       struct data_blob_list_item *rep;
        NTSTATUS status;
 
        /* setup a bind_ack */
@@ -391,20 +457,20 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code
        pkt.u.fault.cancel_count = 0;
        pkt.u.fault.status = fault_code;
 
-       rep = talloc_p(call, struct dcesrv_call_reply);
+       rep = talloc(call, struct data_blob_list_item);
        if (!rep) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
+       status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       dcerpc_set_frag_length(&rep->data, rep->data.length);
+       dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-       DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
-       DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+       DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+       dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
        return NT_STATUS_OK;    
 }
@@ -415,8 +481,8 @@ static NTSTATUS dcesrv_fault(struct dcesrv_call_state *call, uint32_t fault_code
 */
 static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
 {
-       struct dcerpc_packet pkt;
-       struct dcesrv_call_reply *rep;
+       struct ncacn_packet pkt;
+       struct data_blob_list_item *rep;
        NTSTATUS status;
 
        /* setup a bind_nak */
@@ -426,22 +492,24 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
        pkt.ptype = DCERPC_PKT_BIND_NAK;
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
        pkt.u.bind_nak.reject_reason = reason;
-       pkt.u.bind_nak.num_versions = 0;
+       if (pkt.u.bind_nak.reject_reason == DECRPC_BIND_PROTOCOL_VERSION_NOT_SUPPORTED) {
+               pkt.u.bind_nak.versions.v.num_versions = 0;
+       }
 
-       rep = talloc_p(call, struct dcesrv_call_reply);
+       rep = talloc(call, struct data_blob_list_item);
        if (!rep) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = dcerpc_push_auth(&rep->data, call, &pkt, NULL);
+       status = ncacn_push_auth(&rep->blob, call, &pkt, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       dcerpc_set_frag_length(&rep->data, rep->data.length);
+       dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-       DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
-       DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+       DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+       dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
        return NT_STATUS_OK;    
 }
@@ -452,16 +520,20 @@ static NTSTATUS dcesrv_bind_nak(struct dcesrv_call_state *call, uint32_t reason)
 */
 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 {
-       const char *uuid, *transfer_syntax;
        uint32_t if_version, transfer_syntax_version;
-       struct dcerpc_packet pkt;
-       struct dcesrv_call_reply *rep;
+       struct GUID uuid, *transfer_syntax_uuid;
+       struct ncacn_packet pkt;
+       struct data_blob_list_item *rep;
        NTSTATUS status;
        uint32_t result=0, reason=0;
        uint32_t context_id;
        const struct dcesrv_interface *iface;
 
-       if (call->pkt.u.bind.num_contexts != 1 ||
+       if (call->pkt.u.bind.assoc_group_id != 0) {
+               return dcesrv_bind_nak(call, 0);        
+       }
+
+       if (call->pkt.u.bind.num_contexts < 1 ||
            call->pkt.u.bind.ctx_list[0].num_transfer_syntaxes < 1) {
                return dcesrv_bind_nak(call, 0);
        }
@@ -474,24 +546,25 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        }
 
        if_version = call->pkt.u.bind.ctx_list[0].abstract_syntax.if_version;
-       uuid = GUID_string(call, &call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid);
-       if (!uuid) {
-               return dcesrv_bind_nak(call, 0);
-       }
+       uuid = call->pkt.u.bind.ctx_list[0].abstract_syntax.uuid;
 
        transfer_syntax_version = call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].if_version;
-       transfer_syntax = GUID_string(call, 
-                                     &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid);
-       if (!transfer_syntax ||
-           strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
-           NDR_GUID_VERSION != transfer_syntax_version) {
+       transfer_syntax_uuid = &call->pkt.u.bind.ctx_list[0].transfer_syntaxes[0].uuid;
+       if (!GUID_equal(&ndr_transfer_syntax.uuid, transfer_syntax_uuid) != 0 ||
+           ndr_transfer_syntax.if_version != transfer_syntax_version) {
+               char *uuid_str = GUID_string(call, transfer_syntax_uuid);
                /* we only do NDR encoded dcerpc */
+               DEBUG(0,("Non NDR transfer syntax requested - %s\n", uuid_str));
+               talloc_free(uuid_str);
                return dcesrv_bind_nak(call, 0);
        }
 
-       iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
+       iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
        if (iface == NULL) {
-               DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
+               char *uuid_str = GUID_string(call, &uuid);
+               DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
+               talloc_free(uuid_str);
+
                /* we don't know about that interface */
                result = DCERPC_BIND_PROVIDER_REJECT;
                reason = DCERPC_BIND_REASON_ASYNTAX;            
@@ -519,8 +592,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 
        /* handle any authentication that is being requested */
        if (!dcesrv_auth_bind(call)) {
-               /* TODO: work out the right reject code */
-               return dcesrv_bind_nak(call, 0);
+               return dcesrv_bind_nak(call, DCERPC_BIND_REASON_INVALID_AUTH_TYPE);
        }
 
        /* setup a bind_ack */
@@ -531,7 +603,8 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
        pkt.u.bind_ack.max_xmit_frag = 0x2000;
        pkt.u.bind_ack.max_recv_frag = 0x2000;
-       pkt.u.bind_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
+       /* we need to send a non zero assoc_group_id here to make longhorn happy, it also matches samba3 */
+       pkt.u.bind_ack.assoc_group_id = 0x12345678;
        if (iface) {
                /* FIXME: Use pipe name as specified by endpoint instead of interface name */
                pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", iface->name);
@@ -539,44 +612,46 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
                pkt.u.bind_ack.secondary_address = "";
        }
        pkt.u.bind_ack.num_results = 1;
-       pkt.u.bind_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
+       pkt.u.bind_ack.ctx_list = talloc(call, struct dcerpc_ack_ctx);
        if (!pkt.u.bind_ack.ctx_list) {
                return NT_STATUS_NO_MEMORY;
        }
        pkt.u.bind_ack.ctx_list[0].result = result;
        pkt.u.bind_ack.ctx_list[0].reason = reason;
-       GUID_from_string(NDR_GUID, &pkt.u.bind_ack.ctx_list[0].syntax.uuid);
-       pkt.u.bind_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
+       pkt.u.bind_ack.ctx_list[0].syntax = ndr_transfer_syntax;
        pkt.u.bind_ack.auth_info = data_blob(NULL, 0);
 
-       if (!dcesrv_auth_bind_ack(call, &pkt)) {
+       status = dcesrv_auth_bind_ack(call, &pkt);
+       if (!NT_STATUS_IS_OK(status)) {
                return dcesrv_bind_nak(call, 0);
        }
 
        if (iface) {
                status = iface->bind(call, iface);
                if (!NT_STATUS_IS_OK(status)) {
+                       char *uuid_str = GUID_string(call, &uuid);
                        DEBUG(2,("Request for dcerpc interface %s/%d rejected: %s\n", 
-                                uuid, if_version, nt_errstr(status)));
+                                uuid_str, if_version, nt_errstr(status)));
+                       talloc_free(uuid_str);
                        return dcesrv_bind_nak(call, 0);
                }
        }
 
-       rep = talloc(call, struct dcesrv_call_reply);
+       rep = talloc(call, struct data_blob_list_item);
        if (!rep) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = dcerpc_push_auth(&rep->data, call, &pkt, 
+       status = ncacn_push_auth(&rep->blob, call, &pkt, 
                                  call->conn->auth_state.auth_info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       dcerpc_set_frag_length(&rep->data, rep->data.length);
+       dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-       DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
-       DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+       DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+       dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
        return NT_STATUS_OK;
 }
@@ -603,32 +678,29 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 /*
   handle a bind request
 */
-static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32 context_id)
+static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32_t context_id)
 {
        uint32_t if_version, transfer_syntax_version;
-       const char *uuid, *transfer_syntax;
        struct dcesrv_connection_context *context;
        const struct dcesrv_interface *iface;
+       struct GUID uuid, *transfer_syntax_uuid;
 
        if_version = call->pkt.u.alter.ctx_list[0].abstract_syntax.if_version;
-       uuid = GUID_string(call, &call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid);
-       if (!uuid) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       uuid = call->pkt.u.alter.ctx_list[0].abstract_syntax.uuid;
 
        transfer_syntax_version = call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].if_version;
-       transfer_syntax = GUID_string(call, 
-                                     &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid);
-       if (!transfer_syntax ||
-           strcasecmp(NDR_GUID, transfer_syntax) != 0 ||
-           NDR_GUID_VERSION != transfer_syntax_version) {
+       transfer_syntax_uuid = &call->pkt.u.alter.ctx_list[0].transfer_syntaxes[0].uuid;
+       if (!GUID_equal(transfer_syntax_uuid, &ndr_transfer_syntax.uuid) ||
+           ndr_transfer_syntax.if_version != transfer_syntax_version) {
                /* we only do NDR encoded dcerpc */
-               return NT_STATUS_NO_MEMORY;
+               return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
        }
 
-       iface = find_interface_by_uuid(call->conn->endpoint, uuid, if_version);
+       iface = find_interface_by_uuid(call->conn->endpoint, &uuid, if_version);
        if (iface == NULL) {
-               DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid, if_version));
+               char *uuid_str = GUID_string(call, &uuid);
+               DEBUG(2,("Request for unknown dcerpc interface %s/%d\n", uuid_str, if_version));
+               talloc_free(uuid_str);
                return NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED;
        }
 
@@ -650,12 +722,12 @@ static NTSTATUS dcesrv_alter_new_context(struct dcesrv_call_state *call, uint32
 
 
 /*
-  handle a bind request
+  handle a alter context request
 */
 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 {
-       struct dcerpc_packet pkt;
-       struct dcesrv_call_reply *rep;
+       struct ncacn_packet pkt;
+       struct data_blob_list_item *rep;
        NTSTATUS status;
        uint32_t result=0, reason=0;
        uint32_t context_id;
@@ -688,38 +760,43 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
        pkt.u.alter_resp.max_xmit_frag = 0x2000;
        pkt.u.alter_resp.max_recv_frag = 0x2000;
        pkt.u.alter_resp.assoc_group_id = call->pkt.u.alter.assoc_group_id;
-       pkt.u.alter_resp.secondary_address = NULL;
        pkt.u.alter_resp.num_results = 1;
-       pkt.u.alter_resp.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
+       pkt.u.alter_resp.ctx_list = talloc_array(call, struct dcerpc_ack_ctx, 1);
        if (!pkt.u.alter_resp.ctx_list) {
                return NT_STATUS_NO_MEMORY;
        }
        pkt.u.alter_resp.ctx_list[0].result = result;
        pkt.u.alter_resp.ctx_list[0].reason = reason;
-       GUID_from_string(NDR_GUID, &pkt.u.alter_resp.ctx_list[0].syntax.uuid);
-       pkt.u.alter_resp.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
+       pkt.u.alter_resp.ctx_list[0].syntax = ndr_transfer_syntax;
        pkt.u.alter_resp.auth_info = data_blob(NULL, 0);
        pkt.u.alter_resp.secondary_address = "";
 
-       if (!dcesrv_auth_alter_ack(call, &pkt)) {
-               return dcesrv_bind_nak(call, 0);
+       status = dcesrv_auth_alter_ack(call, &pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)
+                   || NT_STATUS_EQUAL(status, NT_STATUS_LOGON_FAILURE)
+                   || NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)
+                   || NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
+                       return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);
+               }
+               return dcesrv_fault(call, 0);
        }
 
-       rep = talloc_p(call, struct dcesrv_call_reply);
+       rep = talloc(call, struct data_blob_list_item);
        if (!rep) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = dcerpc_push_auth(&rep->data, call, &pkt, 
+       status = ncacn_push_auth(&rep->blob, call, &pkt, 
                                  call->conn->auth_state.auth_info);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       dcerpc_set_frag_length(&rep->data, rep->data.length);
+       dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-       DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
-       DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+       DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
+       dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
 
        return NT_STATUS_OK;
 }
@@ -730,28 +807,29 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
 {
        struct ndr_pull *pull;
-       struct ndr_push *push;
-       void *r;
        NTSTATUS status;
-       DATA_BLOB stub;
-       uint32_t total_length;
        struct dcesrv_connection_context *context;
 
-       call->fault_code = 0;
+       /* if authenticated, and the mech we use can't do async replies, don't use them... */
+       if (call->conn->auth_state.gensec_security && 
+           !gensec_have_feature(call->conn->auth_state.gensec_security, GENSEC_FEATURE_ASYNC_REPLIES)) {
+               call->state_flags &= ~DCESRV_CALL_STATE_FLAG_MAY_ASYNC;
+       }
 
        context = dcesrv_find_context(call->conn, call->pkt.u.request.context_id);
        if (context == NULL) {
                return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
        }
 
-       call->context = context;
-
        pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
-       if (!pull) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       NT_STATUS_HAVE_NO_MEMORY(pull);
+
+       pull->flags |= LIBNDR_FLAG_REF_ALLOC;
 
-       if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
+       call->context   = context;
+       call->ndr_pull  = pull;
+
+       if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
                pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
        }
 
@@ -760,7 +838,7 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
        }
 
        /* unravel the NDR for the packet */
-       status = context->iface->ndr_pull(call, call, pull, &r);
+       status = context->iface->ndr_pull(call, call, pull, &call->r);
        if (!NT_STATUS_IS_OK(status)) {
                return dcesrv_fault(call, call->fault_code);
        }
@@ -772,27 +850,53 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
        }
 
        /* call the dispatch function */
-       status = context->iface->dispatch(call, call, r);
+       status = context->iface->dispatch(call, call, call->r);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(5,("dcerpc fault in call %s:%02x - %s\n",
+                        context->iface->name, 
+                        call->pkt.u.request.opnum,
+                        dcerpc_errstr(pull, call->fault_code)));
+               return dcesrv_fault(call, call->fault_code);
+       }
+
+       /* add the call to the pending list */
+       dcesrv_call_set_list(call, DCESRV_LIST_PENDING_CALL_LIST);
+
+       if (call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
+               return NT_STATUS_OK;
+       }
+
+       return dcesrv_reply(call);
+}
+
+_PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call)
+{
+       struct ndr_push *push;
+       NTSTATUS status;
+       DATA_BLOB stub;
+       uint32_t total_length;
+       struct dcesrv_connection_context *context = call->context;
+
+       /* call the reply function */
+       status = context->iface->reply(call, call, call->r);
        if (!NT_STATUS_IS_OK(status)) {
                return dcesrv_fault(call, call->fault_code);
        }
 
        /* form the reply NDR */
        push = ndr_push_init_ctx(call);
-       if (!push) {
-               return NT_STATUS_NO_MEMORY;
-       }
+       NT_STATUS_HAVE_NO_MEMORY(push);
 
        /* carry over the pointer count to the reply in case we are
           using full pointer. See NDR specification for full
           pointers */
-       push->ptr_count = pull->ptr_count;
+       push->ptr_count = call->ndr_pull->ptr_count;
 
        if (lp_rpc_big_endian()) {
                push->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       status = context->iface->ndr_push(call, call, push, r);
+       status = context->iface->ndr_push(call, call, push, call->r);
        if (!NT_STATUS_IS_OK(status)) {
                return dcesrv_fault(call, call->fault_code);
        }
@@ -803,13 +907,11 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
 
        do {
                uint32_t length;
-               struct dcesrv_call_reply *rep;
-               struct dcerpc_packet pkt;
+               struct data_blob_list_item *rep;
+               struct ncacn_packet pkt;
 
-               rep = talloc(call, struct dcesrv_call_reply);
-               if (!rep) {
-                       return NT_STATUS_NO_MEMORY;
-               }
+               rep = talloc(call, struct data_blob_list_item);
+               NT_STATUS_HAVE_NO_MEMORY(rep);
 
                length = stub.length;
                if (length + DCERPC_RESPONSE_LENGTH > call->conn->cli_max_recv_frag) {
@@ -836,23 +938,47 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
                pkt.u.response.stub_and_verifier.data = stub.data;
                pkt.u.response.stub_and_verifier.length = length;
 
-               if (!dcesrv_auth_response(call, &rep->data, &pkt)) {
+               if (!dcesrv_auth_response(call, &rep->blob, &pkt)) {
                        return dcesrv_fault(call, DCERPC_FAULT_OTHER);          
                }
 
-               dcerpc_set_frag_length(&rep->data, rep->data.length);
+               dcerpc_set_frag_length(&rep->blob, rep->blob.length);
 
-               DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
+               DLIST_ADD_END(call->replies, rep, struct data_blob_list_item *);
                
                stub.data += length;
                stub.length -= length;
        } while (stub.length != 0);
 
-       DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+       /* move the call from the pending to the finished calls list */
+       dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
+
+       if (call->conn->call_list && call->conn->call_list->replies) {
+               if (call->conn->transport.report_output_data) {
+                       call->conn->transport.report_output_data(call->conn);
+               }
+       }
 
        return NT_STATUS_OK;
 }
 
+_PUBLIC_ struct socket_address *dcesrv_connection_get_my_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
+{
+       if (!conn->transport.get_my_addr) {
+               return NULL;
+       }
+
+       return conn->transport.get_my_addr(conn, mem_ctx);
+}
+
+_PUBLIC_ struct socket_address *dcesrv_connection_get_peer_addr(struct dcesrv_connection *conn, TALLOC_CTX *mem_ctx)
+{
+       if (!conn->transport.get_peer_addr) {
+               return NULL;
+       }
+
+       return conn->transport.get_peer_addr(conn, mem_ctx);
+}
 
 /*
   work out if we have a full packet yet
@@ -886,6 +1012,15 @@ static void dce_partial_advance(struct dcesrv_connection *dce_conn, uint32_t off
        data_blob_free(&blob);
 }
 
+/*
+  remove the call from the right list when freed
+ */
+static int dcesrv_call_dequeue(struct dcesrv_call_state *call)
+{
+       dcesrv_call_set_list(call, DCESRV_LIST_NONE);
+       return 0;
+}
+
 /*
   process some input to a dcerpc endpoint server.
 */
@@ -896,14 +1031,19 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
        struct dcesrv_call_state *call;
        DATA_BLOB blob;
 
-       call = talloc(dce_conn, struct dcesrv_call_state);
+       call = talloc_zero(dce_conn, struct dcesrv_call_state);
        if (!call) {
                talloc_free(dce_conn->partial_input.data);
                return NT_STATUS_NO_MEMORY;
        }
-       call->conn = dce_conn;
-       call->replies = NULL;
-       call->context = NULL;
+       call->conn              = dce_conn;
+       call->event_ctx         = dce_conn->event_ctx;
+       call->msg_ctx           = dce_conn->msg_ctx;
+       call->state_flags       = call->conn->state_flags;
+       call->time              = timeval_current();
+       call->list              = DCESRV_LIST_NONE;
+
+       talloc_set_destructor(call, dcesrv_call_dequeue);
 
        blob = dce_conn->partial_input;
        blob.length = dcerpc_get_frag_length(&blob);
@@ -919,7 +1059,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
                ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
+       status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, &call->pkt);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(dce_conn->partial_input.data);
                talloc_free(call);
@@ -931,7 +1071,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
        if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
            !dcesrv_auth_request(call, &blob)) {
                dce_partial_advance(dce_conn, blob.length);
-               return dcesrv_fault(call, DCERPC_FAULT_LOGON_FAILURE);          
+               return dcesrv_fault(call, DCERPC_FAULT_ACCESS_DENIED);          
        }
 
        dce_partial_advance(dce_conn, blob.length);
@@ -949,7 +1089,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
 
                /* this is a continuation of an existing call - find the call then
                   tack it on the end */
-               call = dcesrv_find_call(dce_conn, call2->pkt.call_id);
+               call = dcesrv_find_fragmented_call(dce_conn, call2->pkt.call_id);
                if (!call) {
                        return dcesrv_fault(call2, DCERPC_FAULT_OTHER);
                }
@@ -985,12 +1125,15 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
        }
 
        /* this may not be the last pdu in the chain - if its isn't then
-          just put it on the call_list and wait for the rest */
+          just put it on the incoming_fragmented_call_list and wait for the rest */
        if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
            !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
-               DLIST_ADD_END(dce_conn->call_list, call, struct dcesrv_call_state *);
+               dcesrv_call_set_list(call, DCESRV_LIST_FRAGMENTED_CALL_LIST);
                return NT_STATUS_OK;
-       }
+       } 
+       
+       /* This removes any fragments we may have had stashed away */
+       dcesrv_call_set_list(call, DCESRV_LIST_NONE);
 
        switch (call->pkt.ptype) {
        case DCERPC_PKT_BIND:
@@ -1025,7 +1168,7 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
   provide some input to a dcerpc endpoint server. This passes data
   from a dcerpc client into the server
 */
-NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
+_PUBLIC_ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
 {
        NTSTATUS status;
 
@@ -1057,188 +1200,87 @@ NTSTATUS dcesrv_input(struct dcesrv_connection *dce_conn, const DATA_BLOB *data)
 
   The first argument to write_fn() will be 'private', the second will
   be a pointer to a buffer containing the data to be sent and the 3rd
-  will be the number of bytes to be sent.
+  will be a pointer to a size_t variable that will be set to the
+  number of bytes that are consumed from the output.
 
-  write_fn() should return the number of bytes successfully written.
-
-  this will return STATUS_BUFFER_OVERFLOW if there is more to be read
   from the current fragment
 */
-NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
-                      void *private,
-                      ssize_t (*write_fn)(void *, DATA_BLOB *))
+_PUBLIC_ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn, 
+                      void *private_data,
+                      NTSTATUS (*write_fn)(void *private_data, DATA_BLOB *output, size_t *nwritten))
 {
+       NTSTATUS status;
        struct dcesrv_call_state *call;
-       struct dcesrv_call_reply *rep;
-       ssize_t nwritten;
+       struct data_blob_list_item *rep;
+       size_t nwritten;
 
        call = dce_conn->call_list;
        if (!call || !call->replies) {
+               if (dce_conn->pending_call_list) {
+                       /* TODO: we need to say act async here
+                        *       as we know we have pending requests
+                        *       which will be finished at a time
+                        */
+                       return NT_STATUS_FOOBAR;
+               }
                return NT_STATUS_FOOBAR;
        }
        rep = call->replies;
 
-       nwritten = write_fn(private, &rep->data);
-       if (nwritten == -1) {
-               /* TODO: hmm, how do we cope with this? destroy the
-                  connection perhaps? */
-               return NT_STATUS_UNSUCCESSFUL;
-       }
+       status = write_fn(private_data, &rep->blob, &nwritten);
+       NT_STATUS_IS_ERR_RETURN(status);
 
-       rep->data.length -= nwritten;
-       rep->data.data += nwritten;
+       rep->blob.length -= nwritten;
+       rep->blob.data += nwritten;
 
-       if (rep->data.length == 0) {
+       if (rep->blob.length == 0) {
                /* we're done with this section of the call */
                DLIST_REMOVE(call->replies, rep);
-       } else {
-               return STATUS_BUFFER_OVERFLOW;
        }
 
        if (call->replies == NULL) {
                /* we're done with the whole call */
-               DLIST_REMOVE(dce_conn->call_list, call);
+               dcesrv_call_set_list(call, DCESRV_LIST_NONE);
                talloc_free(call);
        }
 
-       return NT_STATUS_OK;
-}
-
-
-/*
-  write_fn() for dcesrv_output_blob()
-*/
-static ssize_t dcesrv_output_blob_write_fn(void *private, DATA_BLOB *out)
-{
-       DATA_BLOB *blob = private;
-       if (out->length < blob->length) {
-               blob->length = out->length;
-       }
-       memcpy(blob->data, out->data, blob->length);
-       return blob->length;
-}
-
-/*
-  a simple wrapper for dcesrv_output() for when we want to output
-  into a data blob
-*/
-NTSTATUS dcesrv_output_blob(struct dcesrv_connection *dce_conn, 
-                           DATA_BLOB *blob)
-{
-       return dcesrv_output(dce_conn, blob, dcesrv_output_blob_write_fn);
-}
-
-/*
-  initialise the dcerpc server context
-*/
-NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **dce_ctx)
-{
-       int i;
-       const char **endpoint_servers = lp_dcerpc_endpoint_servers();
-
-       (*dce_ctx) = talloc_p(mem_ctx, struct dcesrv_context);
-       if (! *dce_ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       (*dce_ctx)->endpoint_list = NULL;
-
-       if (!endpoint_servers) {
-               DEBUG(3,("dcesrv_init_context: no endpoint servers configured\n"));
-               return NT_STATUS_OK;
-       }
-
-       for (i=0;endpoint_servers[i];i++) {
-               NTSTATUS ret;
-               const struct dcesrv_endpoint_server *ep_server;
-               
-               ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
-               if (!ep_server) {
-                       DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
-                       return NT_STATUS_UNSUCCESSFUL;
-               }
-
-               ret = ep_server->init_server(*dce_ctx, ep_server);
-               if (!NT_STATUS_IS_OK(ret)) {
-                       DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
-                       return ret;
-               }
-       }
-
-       return NT_STATUS_OK;
+       return status;
 }
 
-static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
+_PUBLIC_ NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_servers, struct dcesrv_context **_dce_ctx)
 {
+       NTSTATUS status;
        struct dcesrv_context *dce_ctx;
        int i;
-       const char **endpoint_servers = lp_dcerpc_endpoint_servers();
-
-       DEBUG(1,("dcesrv_init\n"));
 
        if (!endpoint_servers) {
                DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
-               return;
-       }
-
-       dce_ctx = talloc_p(service, struct dcesrv_context);
-       if (!dce_ctx) {
-               DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
-               return;
+               return NT_STATUS_INTERNAL_ERROR;
        }
 
-       ZERO_STRUCTP(dce_ctx);
+       dce_ctx = talloc(mem_ctx, struct dcesrv_context);
+       NT_STATUS_HAVE_NO_MEMORY(dce_ctx);
        dce_ctx->endpoint_list  = NULL;
 
        for (i=0;endpoint_servers[i];i++) {
-               NTSTATUS ret;
                const struct dcesrv_endpoint_server *ep_server;
-               
+
                ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
                if (!ep_server) {
                        DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
-                       return;
+                       return NT_STATUS_INTERNAL_ERROR;
                }
 
-               ret = ep_server->init_server(dce_ctx, ep_server);
-               if (!NT_STATUS_IS_OK(ret)) {
-                       DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
-                       return;
+               status = ep_server->init_server(dce_ctx, ep_server);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s': %s\n", endpoint_servers[i],
+                               nt_errstr(status)));
+                       return status;
                }
        }
 
-       dcesrv_sock_init(service, model_ops, dce_ctx);
-
-       return; 
-}
-
-static void dcesrv_accept(struct server_connection *srv_conn)
-{
-       dcesrv_sock_accept(srv_conn);
-}
-
-static void dcesrv_recv(struct server_connection *srv_conn, 
-                       struct timeval t, uint16_t flags)
-{
-       dcesrv_sock_recv(srv_conn, t, flags);
-}
-
-static void dcesrv_send(struct server_connection *srv_conn, 
-                       struct timeval t, uint16_t flags)
-{
-       dcesrv_sock_send(srv_conn, t, flags);
-}
-
-static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
-{
-       dcesrv_sock_close(srv_conn, reason);
-       return; 
-}
-
-static void dcesrv_exit(struct server_service *service, const char *reason)
-{
-       dcesrv_sock_exit(service, reason);
-       return; 
+       *_dce_ctx = dce_ctx;
+       return NT_STATUS_OK;
 }
 
 /* the list of currently registered DCERPC endpoint servers.
@@ -1256,7 +1298,7 @@ static int num_ep_servers;
 
   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
 */
-NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
+_PUBLIC_ NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
 {
        const struct dcesrv_endpoint_server *ep_server = _ep_server;
        
@@ -1322,23 +1364,19 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void)
        return &critical_sizes;
 }
 
-static const struct server_service_ops dcesrv_ops = {
-       .name                   = "rpc",
-       .service_init           = dcesrv_init,
-       .accept_connection      = dcesrv_accept,
-       .recv_handler           = dcesrv_recv,
-       .send_handler           = dcesrv_send,
-       .idle_handler           = NULL,
-       .close_connection       = dcesrv_close,
-       .service_exit           = dcesrv_exit,  
-};
-
-const struct server_service_ops *dcesrv_get_ops(void)
+/*
+  initialise the dcerpc server context for ncacn_np based services
+*/
+_PUBLIC_ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx)
 {
-       return &dcesrv_ops;
-}
+       NTSTATUS status;
+       struct dcesrv_context *dce_ctx;
 
-NTSTATUS server_service_rpc_init(void)
-{
-       return NT_STATUS_OK;    
+       status = dcesrv_init_context(mem_ctx, lp_dcerpc_endpoint_servers(), &dce_ctx);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       *_dce_ctx = dce_ctx;
+       return NT_STATUS_OK;
 }
+
+