~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/rpc_server/remote/dcesrv_remote.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   remote dcerpc operations
 
4
 
 
5
   Copyright (C) Stefan (metze) Metzmacher 2004
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
20
 
 
21
#include "includes.h"
 
22
#include "rpc_server/dcerpc_server.h"
 
23
#include "auth/auth.h"
 
24
#include "auth/credentials/credentials.h"
 
25
#include "librpc/ndr/ndr_table.h"
 
26
#include "param/param.h"
 
27
 
 
28
 
 
29
struct dcesrv_remote_private {
 
30
        struct dcerpc_pipe *c_pipe;
 
31
};
 
32
 
 
33
static NTSTATUS remote_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
 
34
{
 
35
        return NT_STATUS_OK;
 
36
}
 
37
 
 
38
static NTSTATUS remote_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface)
 
39
{
 
40
        NTSTATUS status;
 
41
        const struct ndr_interface_table *table;
 
42
        struct dcesrv_remote_private *priv;
 
43
        const char *binding = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "binding");
 
44
        const char *user, *pass, *domain;
 
45
        struct cli_credentials *credentials;
 
46
        bool machine_account;
 
47
 
 
48
        machine_account = lp_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "use_machine_account", false);
 
49
 
 
50
        priv = talloc(dce_call->conn, struct dcesrv_remote_private);
 
51
        if (!priv) {
 
52
                return NT_STATUS_NO_MEMORY;     
 
53
        }
 
54
        
 
55
        priv->c_pipe = NULL;
 
56
        dce_call->context->private_data = priv;
 
57
 
 
58
        if (!binding) {
 
59
                DEBUG(0,("You must specify a DCE/RPC binding string\n"));
 
60
                return NT_STATUS_INVALID_PARAMETER;
 
61
        }
 
62
 
 
63
        user = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "user");
 
64
        pass = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_remote", "password");
 
65
        domain = lp_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dceprc_remote", "domain");
 
66
 
 
67
        table = ndr_table_by_uuid(&iface->syntax_id.uuid); /* FIXME: What about if_version ? */
 
68
        if (!table) {
 
69
                dce_call->fault_code = DCERPC_FAULT_UNK_IF;
 
70
                return NT_STATUS_NET_WRITE_FAULT;
 
71
        }
 
72
 
 
73
        if (user && pass) {
 
74
                DEBUG(5, ("dcerpc_remote: RPC Proxy: Using specified account\n"));
 
75
                credentials = cli_credentials_init(priv);
 
76
                if (!credentials) {
 
77
                        return NT_STATUS_NO_MEMORY;
 
78
                }
 
79
                cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
 
80
                cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
 
81
                if (domain) {
 
82
                        cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
 
83
                }
 
84
                cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
 
85
        } else if (machine_account) {
 
86
                DEBUG(5, ("dcerpc_remote: RPC Proxy: Using machine account\n"));
 
87
                credentials = cli_credentials_init(priv);
 
88
                cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
 
89
                if (domain) {
 
90
                        cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
 
91
                }
 
92
                status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
 
93
                if (!NT_STATUS_IS_OK(status)) {
 
94
                        return status;
 
95
                }
 
96
        } else if (dce_call->conn->auth_state.session_info->credentials) {
 
97
                DEBUG(5, ("dcerpc_remote: RPC Proxy: Using delegated credentials\n"));
 
98
                credentials = dce_call->conn->auth_state.session_info->credentials;
 
99
        } else {
 
100
                DEBUG(1,("dcerpc_remote: RPC Proxy: You must supply binding, user and password or have delegated credentials\n"));
 
101
                return NT_STATUS_INVALID_PARAMETER;
 
102
        }
 
103
 
 
104
        status = dcerpc_pipe_connect(priv,
 
105
                                     &(priv->c_pipe), binding, table,
 
106
                                     credentials, dce_call->event_ctx,
 
107
                                     dce_call->conn->dce_ctx->lp_ctx);
 
108
 
 
109
        talloc_free(credentials);
 
110
        if (!NT_STATUS_IS_OK(status)) {
 
111
                return status;
 
112
        }
 
113
 
 
114
        return NT_STATUS_OK;    
 
115
}
 
116
 
 
117
static void remote_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
 
118
{
 
119
        struct dcesrv_remote_private *priv = (struct dcesrv_remote_private *)context->private_data;
 
120
 
 
121
        talloc_free(priv->c_pipe);
 
122
 
 
123
        return; 
 
124
}
 
125
 
 
126
static NTSTATUS remote_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
 
127
{
 
128
        enum ndr_err_code ndr_err;
 
129
        const struct ndr_interface_table *table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
 
130
        uint16_t opnum = dce_call->pkt.u.request.opnum;
 
131
 
 
132
        dce_call->fault_code = 0;
 
133
 
 
134
        if (opnum >= table->num_calls) {
 
135
                dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
 
136
                return NT_STATUS_NET_WRITE_FAULT;
 
137
        }
 
138
 
 
139
        *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
 
140
        if (!*r) {
 
141
                return NT_STATUS_NO_MEMORY;
 
142
        }
 
143
 
 
144
        /* unravel the NDR for the packet */
 
145
        ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
 
146
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
147
                dcerpc_log_packet(dce_call->conn->packet_log_dir,
 
148
                                                  table, opnum, NDR_IN,
 
149
                                  &dce_call->pkt.u.request.stub_and_verifier);
 
150
                dce_call->fault_code = DCERPC_FAULT_NDR;
 
151
                return NT_STATUS_NET_WRITE_FAULT;
 
152
        }
 
153
 
 
154
        return NT_STATUS_OK;
 
155
}
 
156
 
 
157
static NTSTATUS remote_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
 
158
{
 
159
        struct dcesrv_remote_private *priv = dce_call->context->private_data;
 
160
        uint16_t opnum = dce_call->pkt.u.request.opnum;
 
161
        const struct ndr_interface_table *table = dce_call->context->iface->private_data;
 
162
        const struct ndr_interface_call *call;
 
163
        const char *name;
 
164
 
 
165
        name = table->calls[opnum].name;
 
166
        call = &table->calls[opnum];
 
167
 
 
168
        if (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
 
169
                ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);            
 
170
        }
 
171
 
 
172
        priv->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
 
173
 
 
174
        /* we didn't use the return code of this function as we only check the last_fault_code */
 
175
        dcerpc_ndr_request(priv->c_pipe, NULL, table, opnum, mem_ctx,r);
 
176
 
 
177
        dce_call->fault_code = priv->c_pipe->last_fault_code;
 
178
        if (dce_call->fault_code != 0) {
 
179
                DEBUG(0,("dcesrv_remote: call[%s] failed with: %s!\n",name, dcerpc_errstr(mem_ctx, dce_call->fault_code)));
 
180
                return NT_STATUS_NET_WRITE_FAULT;
 
181
        }
 
182
 
 
183
        if ((dce_call->fault_code == 0) && 
 
184
            (priv->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT)) {
 
185
                ndr_print_function_debug(call->ndr_print, name, NDR_OUT, r);            
 
186
        }
 
187
 
 
188
        return NT_STATUS_OK;
 
189
}
 
190
 
 
191
static NTSTATUS remote_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
 
192
{
 
193
        enum ndr_err_code ndr_err;
 
194
        const struct ndr_interface_table *table = dce_call->context->iface->private_data;
 
195
        uint16_t opnum = dce_call->pkt.u.request.opnum;
 
196
 
 
197
        /* unravel the NDR for the packet */
 
198
        ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
 
199
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 
200
                dce_call->fault_code = DCERPC_FAULT_NDR;
 
201
                return NT_STATUS_NET_WRITE_FAULT;
 
202
        }
 
203
 
 
204
        return NT_STATUS_OK;
 
205
}
 
206
 
 
207
static NTSTATUS remote_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
 
208
{
 
209
        int i;
 
210
        const struct ndr_interface_table *table = iface->private_data;
 
211
 
 
212
        for (i=0;i<table->endpoints->count;i++) {
 
213
                NTSTATUS ret;
 
214
                const char *name = table->endpoints->names[i];
 
215
 
 
216
                ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
 
217
                if (!NT_STATUS_IS_OK(ret)) {
 
218
                        DEBUG(1,("remote_op_init_server: failed to register endpoint '%s'\n",name));
 
219
                        return ret;
 
220
                }
 
221
        }
 
222
 
 
223
        return NT_STATUS_OK;
 
224
}
 
225
 
 
226
static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
 
227
{
 
228
        int i;
 
229
        const char **ifaces = (const char **)str_list_make(dce_ctx, lp_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_remote", "interfaces"),NULL);
 
230
 
 
231
        if (!ifaces) {
 
232
                DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
 
233
                return NT_STATUS_OK;
 
234
        }
 
235
 
 
236
        for (i=0;ifaces[i];i++) {
 
237
                NTSTATUS ret;
 
238
                struct dcesrv_interface iface;
 
239
                
 
240
                if (!ep_server->interface_by_name(&iface, ifaces[i])) {
 
241
                        DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
 
242
                        talloc_free(ifaces);
 
243
                        return NT_STATUS_UNSUCCESSFUL;
 
244
                }
 
245
 
 
246
                ret = remote_register_one_iface(dce_ctx, &iface);
 
247
                if (!NT_STATUS_IS_OK(ret)) {
 
248
                        DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
 
249
                        talloc_free(ifaces);
 
250
                        return ret;
 
251
                }
 
252
        }
 
253
 
 
254
        talloc_free(ifaces);
 
255
        return NT_STATUS_OK;
 
256
}
 
257
 
 
258
static bool remote_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *if_tabl)
 
259
{
 
260
        iface->name = if_tabl->name;
 
261
        iface->syntax_id = if_tabl->syntax_id;
 
262
        
 
263
        iface->bind = remote_op_bind;
 
264
        iface->unbind = remote_op_unbind;
 
265
 
 
266
        iface->ndr_pull = remote_op_ndr_pull;
 
267
        iface->dispatch = remote_op_dispatch;
 
268
        iface->reply = remote_op_reply;
 
269
        iface->ndr_push = remote_op_ndr_push;
 
270
 
 
271
        iface->private_data = if_tabl;
 
272
 
 
273
        return true;
 
274
}
 
275
 
 
276
static bool remote_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
 
277
{
 
278
        const struct ndr_interface_list *l;
 
279
 
 
280
        for (l=ndr_table_list();l;l=l->next) {
 
281
                if (l->table->syntax_id.if_version == if_version &&
 
282
                        GUID_equal(&l->table->syntax_id.uuid, uuid)==0) {
 
283
                        return remote_fill_interface(iface, l->table);
 
284
                }
 
285
        }
 
286
 
 
287
        return false;   
 
288
}
 
289
 
 
290
static bool remote_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
 
291
{
 
292
        const struct ndr_interface_table *tbl = ndr_table_by_name(name);
 
293
 
 
294
        if (tbl)
 
295
                return remote_fill_interface(iface, tbl);
 
296
 
 
297
        return false;   
 
298
}
 
299
 
 
300
NTSTATUS dcerpc_server_remote_init(void)
 
301
{
 
302
        NTSTATUS ret;
 
303
        struct dcesrv_endpoint_server ep_server;
 
304
 
 
305
        ZERO_STRUCT(ep_server);
 
306
 
 
307
        /* fill in our name */
 
308
        ep_server.name = "remote";
 
309
 
 
310
        /* fill in all the operations */
 
311
        ep_server.init_server = remote_op_init_server;
 
312
 
 
313
        ep_server.interface_by_uuid = remote_op_interface_by_uuid;
 
314
        ep_server.interface_by_name = remote_op_interface_by_name;
 
315
 
 
316
        /* register ourselves with the DCERPC subsystem. */
 
317
        ret = dcerpc_register_ep_server(&ep_server);
 
318
        if (!NT_STATUS_IS_OK(ret)) {
 
319
                DEBUG(0,("Failed to register 'remote' endpoint server!\n"));
 
320
                return ret;
 
321
        }
 
322
 
 
323
        /* We need the full DCE/RPC interface table */
 
324
        ndr_table_init();
 
325
 
 
326
        return ret;
 
327
}