s4:rpc_server Record the remote connections association group ID
[abartlet/samba.git/.git] / source4 / rpc_server / remote / dcesrv_remote.c
index 1310ecee90e04c5b0c3ddce4344731d2983b5ff6..9c4174be96bfe53d9ef29fdfea5e9f6469f19bb7 100644 (file)
@@ -3,7 +3,9 @@
    remote dcerpc operations
 
    Copyright (C) Stefan (metze) Metzmacher 2004
-   
+   Copyright (C) Julien Kerihuel 2008-2009
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2010
+
    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 3 of the License, or
@@ -39,21 +41,24 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
 {
         NTSTATUS status;
        const struct ndr_interface_table *table;
-        struct dcesrv_remote_private *private;
+       struct dcesrv_remote_private *priv;
        const char *binding = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "binding");
        const char *user, *pass, *domain;
        struct cli_credentials *credentials;
+       bool must_free_credentials = true;
        bool machine_account;
+       struct dcerpc_binding           *b;
+       struct composite_context        *pipe_conn_req;
 
        machine_account = lp_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "use_machine_account", false);
 
-       private = talloc(dce_call->conn, struct dcesrv_remote_private);
-       if (!private) {
+       priv = talloc(dce_call->conn, struct dcesrv_remote_private);
+       if (!priv) {
                return NT_STATUS_NO_MEMORY;     
        }
        
-       private->c_pipe = NULL;
-       dce_call->context->private = private;
+       priv->c_pipe = NULL;
+       dce_call->context->private_data = priv;
 
        if (!binding) {
                DEBUG(0,("You must specify a DCE/RPC binding string\n"));
@@ -72,7 +77,7 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
 
        if (user && pass) {
                DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
-               credentials = cli_credentials_init(private);
+               credentials = cli_credentials_init(priv);
                if (!credentials) {
                        return NT_STATUS_NO_MEMORY;
                }
@@ -84,7 +89,7 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
                cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
        } else if (machine_account) {
                DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
-               credentials = cli_credentials_init(private);
+               credentials = cli_credentials_init(priv);
                cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
                if (domain) {
                        cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
@@ -96,17 +101,42 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
        } else if (dce_call->conn->auth_state.session_info->credentials) {
                DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
                credentials = dce_call->conn->auth_state.session_info->credentials;
+               must_free_credentials = false;
        } else {
                DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       status = dcerpc_pipe_connect(private, 
-                                    &(private->c_pipe), binding, table,
-                                    credentials, dce_call->event_ctx,
-                                    dce_call->conn->dce_ctx->lp_ctx);
+       /* parse binding string to the structure */
+       status = dcerpc_parse_binding(dce_call->context, binding, &b);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
+               return status;
+       }
+       
+       DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
+       
+       /* If we already have a remote association group ID, then use that */
+       if (dce_call->context->assoc_group->proxied_id != 0) {
+               b->assoc_group_id = dce_call->context->assoc_group->proxied_id;
+       }
+
+       pipe_conn_req = dcerpc_pipe_connect_b_send(dce_call->context, b, table,
+                                                  credentials, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
+       status = dcerpc_pipe_connect_b_recv(pipe_conn_req, dce_call->context, &(priv->c_pipe));
+       
+       if (must_free_credentials) {
+               talloc_free(credentials);
+       }
+
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (dce_call->context->assoc_group->proxied_id == 0) {
+               dce_call->context->assoc_group->proxied_id = priv->c_pipe->assoc_group_id;
+       }
 
-       talloc_free(credentials);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -116,9 +146,9 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
 
 static void remote_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
 {
-       struct dcesrv_remote_private *private = (struct dcesrv_remote_private *)context->private;
+       struct dcesrv_remote_private *priv = (struct dcesrv_remote_private *)context->private_data;
 
-       talloc_free(private->c_pipe);
+       talloc_free(priv->c_pipe);
 
        return; 
 }
@@ -126,7 +156,7 @@ static void remote_op_unbind(struct dcesrv_connection_context *context, const st
 static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
 {
        enum ndr_err_code ndr_err;
-       const struct ndr_interface_table *table = (const struct ndr_interface_table *)dce_call->context->iface->private;
+       const struct ndr_interface_table *table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
        uint16_t opnum = dce_call->pkt.u.request.opnum;
 
        dce_call->fault_code = 0;
@@ -156,32 +186,32 @@ static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CT
 
 static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
 {
-       struct dcesrv_remote_private *private = dce_call->context->private;
+       struct dcesrv_remote_private *priv = dce_call->context->private_data;
        uint16_t opnum = dce_call->pkt.u.request.opnum;
-       const struct ndr_interface_table *table = dce_call->context->iface->private;
+       const struct ndr_interface_table *table = dce_call->context->iface->private_data;
        const struct ndr_interface_call *call;
        const char *name;
 
        name = table->calls[opnum].name;
        call = &table->calls[opnum];
 
-       if (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
+       if (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
                ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);            
        }
 
-       private->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
+       priv->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
 
        /* we didn't use the return code of this function as we only check the last_fault_code */
-       dcerpc_ndr_request(private->c_pipe, NULL, table, opnum, mem_ctx,r);
+       dcerpc_ndr_request(priv->c_pipe, NULL, table, opnum, mem_ctx,r);
 
-       dce_call->fault_code = private->c_pipe->last_fault_code;
+       dce_call->fault_code = priv->c_pipe->last_fault_code;
        if (dce_call->fault_code != 0) {
                DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",name, dcerpc_errstr(mem_ctx, dce_call->fault_code)));
                return NT_STATUS_NET_WRITE_FAULT;
        }
 
        if ((dce_call->fault_code == 0) && 
-           (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
+           (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
                ndr_print_function_debug(call->ndr_print, name, NDR_OUT, r);            
        }
 
@@ -191,7 +221,7 @@ static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CT
 static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
 {
        enum ndr_err_code ndr_err;
-       const struct ndr_interface_table *table = dce_call->context->iface->private;
+       const struct ndr_interface_table *table = dce_call->context->iface->private_data;
        uint16_t opnum = dce_call->pkt.u.request.opnum;
 
         /* unravel the NDR for the packet */
@@ -207,7 +237,7 @@ static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CT
 static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
 {
        int i;
-       const struct ndr_interface_table *table = iface->private;
+       const struct ndr_interface_table *table = iface->private_data;
 
        for (i=0;i<table->endpoints->count;i++) {
                NTSTATUS ret;
@@ -268,7 +298,7 @@ static bool remote_fill_interface(struct dcesrv_interface *iface, const struct n
        iface->reply = remote_op_reply;
        iface->ndr_push = remote_op_ndr_push;
 
-       iface->private = if_tabl;
+       iface->private_data = if_tabl;
 
        return true;
 }