r4359: using talloc_free() of a child struct in a talloc_destructor is useless
[samba.git] / source4 / rpc_server / dcerpc_server.c
index fe58ee53ee732e845709608d02eade313bfb13e7..c53036b45b7261d057c043e7054c7ca0f2e6c420 100644 (file)
@@ -69,11 +69,11 @@ static struct dcesrv_endpoint *find_endpoint(struct dcesrv_context *dce_ctx,
 static BOOL interface_match(const struct dcesrv_interface *if1,
                                                        const struct dcesrv_interface *if2)
 {
-       if (if1->ndr->if_version != if2->ndr->if_version) {
+       if (if1->if_version != if2->if_version) {
                return False;
        }
 
-       if (strcmp(if1->ndr->uuid, if2->ndr->uuid)==0) {
+       if (strcmp(if1->uuid, if2->uuid)==0) {
                return True;
        }                       
 
@@ -101,11 +101,11 @@ static const struct dcesrv_interface *find_interface(const struct dcesrv_endpoin
 static BOOL interface_match_by_uuid(const struct dcesrv_interface *iface,
                                    const char *uuid, uint32_t if_version)
 {
-       if (iface->ndr->if_version != if_version) {
+       if (iface->if_version != if_version) {
                return False;
        }
 
-       if (strcmp(iface->ndr->uuid, uuid)==0) {
+       if (strcmp(iface->uuid, uuid)==0) {
                return True;
        }                       
 
@@ -177,7 +177,7 @@ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
        /* see if the interface is already registered on te endpoint */
        if (find_interface(ep, iface)!=NULL) {
                DEBUG(0,("dcesrv_interface_register: interface '%s' already registered on endpoint '%s'\n",
-                       iface->ndr->name, ep_name));
+                       iface->name, ep_name));
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
@@ -198,7 +198,7 @@ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
                 * we try to set it
                 */
                if (ep->sd == NULL) {
-                       ep->sd = copy_security_descriptor(dce_ctx, sd);
+                       ep->sd = security_descriptor_copy(dce_ctx, sd);
                }
 
                /* if now there's no security descriptor given on the endpoint
@@ -208,7 +208,7 @@ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
                if (ep->sd != NULL) {
                        DEBUG(0,("dcesrv_interface_register: interface '%s' failed to setup a security descriptor\n"
                                 "                           on endpoint '%s'\n",
-                               iface->ndr->name, ep_name));
+                               iface->name, ep_name));
                        if (add_ep) free(ep);
                        free(ifl);
                        return NT_STATUS_OBJECT_NAME_COLLISION;
@@ -224,7 +224,7 @@ NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
        }
 
        DEBUG(4,("dcesrv_interface_register: interface '%s' registered on endpoint '%s'\n",
-               iface->ndr->name, ep_name));
+               iface->name, ep_name));
 
        return NT_STATUS_OK;
 }
@@ -243,7 +243,7 @@ NTSTATUS dcesrv_generic_session_key(struct dcesrv_connection *p,
                                    DATA_BLOB *session_key)
 {
        /* this took quite a few CPU cycles to find ... */
-       session_key->data = discard_const_p(char, "SystemLibraryDTC");
+       session_key->data = discard_const_p(uint8_t, "SystemLibraryDTC");
        session_key->length = 16;
        return NT_STATUS_OK;
 }
@@ -273,10 +273,6 @@ static int dcesrv_endpoint_destructor(void *ptr)
                dcesrv_handle_destroy(p, p->handles);
        }
 
-       if (p->auth_state.gensec_security) {
-               gensec_end(&p->auth_state.gensec_security);
-       }
-
        return 0;
 }
 
@@ -497,10 +493,10 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
        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;
-       if (call->conn->iface && call->conn->iface->ndr) {
+       if (call->conn->iface) {
                /* FIXME: Use pipe name as specified by endpoint instead of interface name */
                pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "\\PIPE\\%s", 
-                                                                  call->conn->iface->ndr->name);
+                                                                  call->conn->iface->name);
        } else {
                pkt.u.bind_ack.secondary_address = "";
        }
@@ -564,6 +560,65 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
        return NT_STATUS_OK;
 }
 
+/*
+  handle a bind request
+*/
+static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
+{
+       struct dcerpc_packet pkt;
+       struct dcesrv_call_reply *rep;
+       NTSTATUS status;
+       uint32_t result=0, reason=0;
+
+       /* handle any authentication that is being requested */
+       if (!dcesrv_auth_alter(call)) {
+               /* TODO: work out the right reject code */
+               return dcesrv_bind_nak(call, 0);
+       }
+
+       /* setup a alter_ack */
+       dcesrv_init_hdr(&pkt);
+       pkt.auth_length = 0;
+       pkt.call_id = call->pkt.call_id;
+       pkt.ptype = DCERPC_PKT_ALTER_ACK;
+       pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+       pkt.u.alter_ack.max_xmit_frag = 0x2000;
+       pkt.u.alter_ack.max_recv_frag = 0x2000;
+       pkt.u.alter_ack.assoc_group_id = call->pkt.u.bind.assoc_group_id;
+       pkt.u.alter_ack.secondary_address = NULL;
+       pkt.u.alter_ack.num_results = 1;
+       pkt.u.alter_ack.ctx_list = talloc_p(call, struct dcerpc_ack_ctx);
+       if (!pkt.u.alter_ack.ctx_list) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       pkt.u.alter_ack.ctx_list[0].result = result;
+       pkt.u.alter_ack.ctx_list[0].reason = reason;
+       GUID_from_string(NDR_GUID, &pkt.u.alter_ack.ctx_list[0].syntax.uuid);
+       pkt.u.alter_ack.ctx_list[0].syntax.if_version = NDR_GUID_VERSION;
+       pkt.u.alter_ack.auth_info = data_blob(NULL, 0);
+
+       if (!dcesrv_auth_alter_ack(call, &pkt)) {
+               return dcesrv_bind_nak(call, 0);
+       }
+
+       rep = talloc_p(call, struct dcesrv_call_reply);
+       if (!rep) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = dcerpc_push_auth(&rep->data, 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);
+
+       DLIST_ADD_END(call->replies, rep, struct dcesrv_call_reply *);
+       DLIST_ADD_END(call->conn->call_list, call, struct dcesrv_call_state *);
+
+       return NT_STATUS_OK;
+}
 
 /*
   handle a dcerpc request packet
@@ -572,31 +627,24 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
 {
        struct ndr_pull *pull;
        struct ndr_push *push;
-       uint16_t opnum;
        void *r;
        NTSTATUS status;
        DATA_BLOB stub;
        uint32_t total_length;
 
+       call->fault_code = 0;
 
        if (!call->conn->iface) {
                return dcesrv_fault(call, DCERPC_FAULT_UNK_IF);
        }
 
-       opnum = call->pkt.u.request.opnum;
-
-       if (opnum >= call->conn->iface->ndr->num_calls) {
-               return dcesrv_fault(call, DCERPC_FAULT_OP_RNG_ERROR);
-       }
-
        pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier, call);
        if (!pull) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       r = talloc(call, call->conn->iface->ndr->calls[opnum].struct_size);
-       if (!r) {
-               return NT_STATUS_NO_MEMORY;
+       if (call->pkt.pfc_flags & DCERPC_PFC_FLAG_ORPC) {
+               pull->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
        }
 
        if (!(call->pkt.drep[0] & DCERPC_DREP_LE)) {
@@ -604,11 +652,9 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
        }
 
        /* unravel the NDR for the packet */
-       status = call->conn->iface->ndr->calls[opnum].ndr_pull(pull, NDR_IN, r);
+       status = call->conn->iface->ndr_pull(call, call, pull, &r);
        if (!NT_STATUS_IS_OK(status)) {
-               dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
-                                 &call->pkt.u.request.stub_and_verifier);
-               return dcesrv_fault(call, DCERPC_FAULT_NDR);
+               return dcesrv_fault(call, call->fault_code);
        }
 
        if (pull->offset != pull->data_size) {
@@ -617,13 +663,9 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
                dump_data(10, pull->data+pull->offset, pull->data_size - pull->offset);
        }
 
-       call->fault_code = 0;
-
        /* call the dispatch function */
        status = call->conn->iface->dispatch(call, call, r);
        if (!NT_STATUS_IS_OK(status)) {
-               dcerpc_log_packet(call->conn->iface->ndr, opnum, NDR_IN, 
-                                 &call->pkt.u.request.stub_and_verifier);
                return dcesrv_fault(call, call->fault_code);
        }
 
@@ -642,9 +684,9 @@ static NTSTATUS dcesrv_request(struct dcesrv_call_state *call)
                push->flags |= LIBNDR_FLAG_BIGENDIAN;
        }
 
-       status = call->conn->iface->ndr->calls[opnum].ndr_push(push, NDR_OUT, r);
+       status = call->conn->iface->ndr_push(call, call, push, r);
        if (!NT_STATUS_IS_OK(status)) {
-               return dcesrv_fault(call, DCERPC_FAULT_NDR);
+               return dcesrv_fault(call, call->fault_code);
        }
 
        stub = ndr_push_blob(push);
@@ -786,7 +828,8 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
        dce_partial_advance(dce_conn, blob.length);
 
        /* see if this is a continued packet */
-       if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
+       if (call->pkt.ptype == DCERPC_PKT_REQUEST &&
+           !(call->pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
                struct dcesrv_call_state *call2 = call;
                uint32_t alloc_size;
 
@@ -832,7 +875,8 @@ 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 */
-       if (!(call->pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
+       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 *);
                return NT_STATUS_OK;
        }
@@ -844,6 +888,9 @@ NTSTATUS dcesrv_input_process(struct dcesrv_connection *dce_conn)
        case DCERPC_PKT_AUTH3:
                status = dcesrv_auth3(call);
                break;
+       case DCERPC_PKT_ALTER:
+               status = dcesrv_alter(call);
+               break;
        case DCERPC_PKT_REQUEST:
                status = dcesrv_request(call);
                break;
@@ -932,6 +979,8 @@ NTSTATUS dcesrv_output(struct dcesrv_connection *dce_conn,
        if (rep->data.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) {
@@ -1056,21 +1105,18 @@ static void dcesrv_accept(struct server_connection *srv_conn)
        dcesrv_sock_accept(srv_conn);
 }
 
-static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
+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, time_t t, uint16_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_idle(struct server_connection *srv_conn, time_t t)
-{
-       dcesrv_sock_idle(srv_conn, t);
-}
-
 static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
 {
        dcesrv_sock_close(srv_conn, reason);
@@ -1085,7 +1131,7 @@ static void dcesrv_exit(struct server_service *service, const char *reason)
 
 /* the list of currently registered DCERPC endpoint servers.
  */
-static struct {
+static struct ep_server {
        struct dcesrv_endpoint_server *ep_server;
 } *ep_servers = NULL;
 static int num_ep_servers;
@@ -1098,7 +1144,7 @@ static int num_ep_servers;
 
   The 'type' is used to specify whether this is for a disk, printer or IPC$ share
 */
-static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
+NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
 {
        const struct dcesrv_endpoint_server *ep_server = _ep_server;
        
@@ -1109,7 +1155,7 @@ static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
                return NT_STATUS_OBJECT_NAME_COLLISION;
        }
 
-       ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1));
+       ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1);
        if (!ep_servers) {
                smb_panic("out of memory in dcerpc_register");
        }
@@ -1164,32 +1210,13 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void)
        return &critical_sizes;
 }
 
-/*
-  initialise the DCERPC subsystem
-*/
-BOOL subsystem_dcerpc_init(void)
-{
-       NTSTATUS status;
-
-       status = register_subsystem("dcerpc", dcerpc_register_ep_server); 
-       if (!NT_STATUS_IS_OK(status)) {
-               return False;
-       }
-
-       /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPPER, fails to initialise? */
-       static_init_dcerpc;
-
-       DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
-       return True;
-}
-
 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           = dcesrv_idle,
+       .idle_handler           = NULL,
        .close_connection       = dcesrv_close,
        .service_exit           = dcesrv_exit,  
 };