s4:rpc_server Add a 'if_version' parameter to the bind operation.
[abartlet/samba.git/.git] / source4 / rpc_server / remote / dcesrv_remote.c
index 7354854e9c664c0606d205a7353d6565a325a655..45944bc227ecacb973989156339c4ea04c4022a6 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
@@ -35,7 +37,7 @@ static NTSTATUS remote_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *
        return NT_STATUS_OK;
 }
 
-static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
+static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
 {
         NTSTATUS status;
        const struct ndr_interface_table *table;
@@ -43,7 +45,10 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
        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);
 
@@ -53,7 +58,7 @@ static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct
        }
        
        priv->c_pipe = NULL;
-       dce_call->context->private = priv;
+       dce_call->context->private_data = priv;
 
        if (!binding) {
                DEBUG(0,("You must specify a DCE/RPC binding string\n"));
@@ -96,17 +101,44 @@ 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(priv,
-                                    &(priv->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;
+       }
+
+       b->object.if_version = if_version;
+
+       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,7 +148,7 @@ 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 *priv = (struct dcesrv_remote_private *)context->private;
+       struct dcesrv_remote_private *priv = (struct dcesrv_remote_private *)context->private_data;
 
        talloc_free(priv->c_pipe);
 
@@ -126,7 +158,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,9 +188,9 @@ 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 *priv = 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;
 
@@ -191,7 +223,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 +239,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 +300,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;
 }