mapiproxy: Update to reflect samba4 API change.
[tridge/openchange.git] / trunk / mapiproxy / dcesrv_mapiproxy.c
1 /*
2    MAPI Proxy
3
4    This proxy is based on dcesrv_remote.c code from Stefan Metzemacher
5
6    OpenChange Project
7
8    Copyright (C) Julien Kerihuel 2008-2011
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "mapiproxy/dcesrv_mapiproxy.h"
25 #include "mapiproxy/dcesrv_mapiproxy_proto.h"
26 #include <dlinklist.h>
27 #include "libmapi/libmapi.h"
28 #include "libmapi/libmapi_private.h"
29 #include <util/debug.h>
30
31 /**
32    \file dcesrv_mapiproxy.c
33
34    \brief mapiproxy main file
35  */
36
37
38 static NTSTATUS mapiproxy_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
39 {
40         DEBUG(5, ("mapiproxy::mapiproxy_op_reply\n"));
41         return NT_STATUS_OK;
42 }
43
44 static NTSTATUS mapiproxy_op_connect(struct dcesrv_call_state *dce_call, 
45                                      const struct ndr_interface_table *table,
46                                      const char *binding)
47 {
48         NTSTATUS                                status;
49         struct dcesrv_mapiproxy_private         *private_data;
50         const char                              *user;
51         const char                              *pass;
52         const char                              *domain;
53         struct cli_credentials                  *credentials;
54         bool                                    acquired_creds = false;
55         bool                                    machine_account;
56
57         DEBUG(5, ("mapiproxy::mapiproxy_op_connect\n"));
58
59         /* Retrieve the binding string from parametric options if undefined */
60         if (!binding) {
61                 binding = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "binding");
62                 if (!binding) {
63                         DEBUG(0, ("You must specify a DCE/RPC binding string\n"));
64                         return NT_STATUS_INVALID_PARAMETER;
65                 }
66         }
67
68         /* Retrieve parametric options */
69         machine_account = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "use_machine_account", false);
70         user = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "username");
71         pass = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "password");
72         domain = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "domain");
73
74         /* Retrieve private mapiproxy data */
75         private_data = (struct dcesrv_mapiproxy_private *) dce_call->context->private_data;
76
77         if (user && pass) {
78                 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using specified account\n"));
79                 credentials = cli_credentials_init(private_data);
80                 if (!credentials) {
81                         return NT_STATUS_NO_MEMORY;
82                 }
83
84                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
85                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
86                 if (domain) {
87                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
88                 }
89                 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
90         } else if (machine_account) {
91                 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using machine account\n"));
92                 credentials = cli_credentials_init(private_data);
93                 if (!credentials) {
94                         return NT_STATUS_NO_MEMORY;
95                 }
96                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
97                 if (domain) {
98                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
99                 }
100                 status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
101                 if (!NT_STATUS_IS_OK(status)) {
102                         return status;
103                 }
104         } else if (dce_call->conn->auth_state.session_info->credentials) {
105                 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using delegated credentials\n"));
106                 credentials = dce_call->conn->auth_state.session_info->credentials;
107                 acquired_creds = true;
108         } else if (private_data->credentials) {
109                 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using acquired deletegated credentials\n"));
110                 credentials = private_data->credentials;
111                 acquired_creds = true;
112         } else {
113                 DEBUG(1, ("dcerpc_mapiproxy: RPC proxy: You must supply binding, user and password or have delegated credentials\n"));
114                 return NT_STATUS_INVALID_PARAMETER;
115         }
116
117         if (((dce_call->pkt.ptype == DCERPC_PKT_BIND) && dce_call->pkt.u.bind.assoc_group_id) ||
118             ((dce_call->pkt.ptype == DCERPC_PKT_ALTER) && dce_call->pkt.u.alter.assoc_group_id)) {
119                 struct dcerpc_binding           *b;
120                 struct composite_context        *pipe_conn_req;
121
122                 /* parse binding string to the structure */
123                 status = dcerpc_parse_binding(dce_call->context, binding, &b);
124                 if (!NT_STATUS_IS_OK(status)) {
125                         DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
126                         return status;
127                 }
128                 
129                 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
130                 
131                 switch (dce_call->pkt.ptype) {
132                 case DCERPC_PKT_BIND:
133                         b->assoc_group_id = dce_call->pkt.u.bind.assoc_group_id;
134                         break;
135                 case DCERPC_PKT_ALTER:
136                         b->assoc_group_id = dce_call->pkt.u.alter.assoc_group_id;
137                         break;
138                 default:
139                         break;
140                 }
141                 
142                 pipe_conn_req = dcerpc_pipe_connect_b_send(dce_call->context, b, table,
143                                                            credentials, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
144                 status = dcerpc_pipe_connect_b_recv(pipe_conn_req, dce_call->context, &(private_data->c_pipe));
145
146                 if (acquired_creds == false) {
147                         talloc_free(credentials);
148                 }
149
150                 if (!NT_STATUS_IS_OK(status)) {
151                         return status;
152                 }
153                 dce_call->context->assoc_group->id = private_data->c_pipe->assoc_group_id;
154                 
155         } else {
156                 status = dcerpc_pipe_connect(dce_call->context,
157                                              &(private_data->c_pipe), binding, table,
158                                              credentials, dce_call->event_ctx,
159                                              dce_call->conn->dce_ctx->lp_ctx);
160                 
161                 if (acquired_creds == false) {
162                         talloc_free(credentials);
163                 }
164
165                 if (!NT_STATUS_IS_OK(status)) {
166                         return status;
167                 }
168                 dce_call->context->assoc_group->id = private_data->c_pipe->assoc_group_id;
169         }
170
171         private_data->connected = true;
172
173         DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: CONNECTED\n"));
174
175         return NT_STATUS_OK;
176 }
177
178 static NTSTATUS mapiproxy_op_bind_proxy(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
179 {
180         NTSTATUS                                status = NT_STATUS_OK;
181         const struct ndr_interface_table        *table;
182         struct dcesrv_mapiproxy_private         *private_data;
183         bool                                    delegated;
184
185         /* Retrieve private mapiproxy data */
186         private_data = (struct dcesrv_mapiproxy_private *)dce_call->context->private_data;
187
188         table = ndr_table_by_uuid(&iface->syntax_id.uuid);
189         if (!table) {
190                 dce_call->fault_code = DCERPC_FAULT_UNK_IF;
191                 return NT_STATUS_NET_WRITE_FAULT;
192         }
193
194         if (dce_call->conn->auth_state.session_info->credentials) {
195                 private_data->credentials = dce_call->conn->auth_state.session_info->credentials;
196                 DEBUG(5, ("dcerpc_mapiproxy: Delegated credentials acquired\n"));
197         }
198
199         delegated = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "delegated_auth", false);
200         if (delegated == false) {
201                 status = mapiproxy_op_connect(dce_call, table, NULL);
202         }
203
204         return status;
205 }
206
207
208 /**
209    \details This function is called when the client binds to one of
210    the interfaces mapiproxy handles.
211
212    \param dce_call pointer to the session context
213    \param iface pointer to the dcesrv interface structure with
214    function hooks
215    \param if_version the version of the pipe
216
217    \return NT_STATUS_OK on success, otherwise NTSTATUS error
218  */
219 static NTSTATUS mapiproxy_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
220 {
221         struct dcesrv_mapiproxy_private         *private_data;
222         bool                                    server_mode;
223
224         DEBUG(5, ("mapiproxy::mapiproxy_op_bind: [session = 0x%x] [session server id = 0x%"PRIx64" 0x%x 0x%x]\n", dce_call->context->context_id,
225                   dce_call->conn->server_id.id, dce_call->conn->server_id.id2, dce_call->conn->server_id.node));
226
227         /* Retrieve server mode parametric option */
228         server_mode = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "server", false);
229
230         /* Initialize private structure */
231         private_data = talloc(dce_call->context, struct dcesrv_mapiproxy_private);
232         if (!private_data) {
233                 return NT_STATUS_NO_MEMORY;
234         }
235         
236         private_data->c_pipe = NULL;
237         private_data->exchname = NULL;
238         private_data->server_mode = server_mode;
239         private_data->connected = false;
240
241         dce_call->context->private_data = private_data;
242
243         if (server_mode == false) {
244           return mapiproxy_op_bind_proxy(dce_call, iface, if_version);
245         }
246
247         return NT_STATUS_OK;
248 }
249
250
251 /**
252    \details Called when the client disconnects from one of the
253    endpoints managed by mapiproxy.
254
255    \param context pointer to the connection context
256    \param iface pointer to the dcesrv interface structure with
257    function hooks
258  */
259 static void mapiproxy_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
260 {
261         struct dcesrv_mapiproxy_private *private_data = (struct dcesrv_mapiproxy_private *) context->private_data;
262
263         DEBUG(5, ("mapiproxy::mapiproxy_op_unbind\n"));
264
265         mapiproxy_module_unbind(context->conn->server_id, context->context_id);
266         mapiproxy_server_unbind(context->conn->server_id, context->context_id);
267
268         if (private_data) {
269                 talloc_free(private_data->c_pipe);
270                 talloc_free(private_data);
271         }
272
273         talloc_free(context);
274
275         return;
276 }
277
278
279 /**
280    \details This is the function called when mapiproxy receives a
281    request. The request has already been extracted and its information
282    filled into structures
283
284    \param dce_call pointer to the session context
285    \param mem_ctx pointer to the memory context
286    \param pull pointer on pointer to the ndr_pull structure
287    \param r generic pointer on pointer to the pulled ndr content
288
289    \return NT_STATUS_OK on success, other NTSTATUS error
290  */
291 static NTSTATUS mapiproxy_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
292 {
293         NTSTATUS                                status;
294         enum ndr_err_code                       ndr_err;
295         const struct ndr_interface_table        *table;
296         uint16_t                                opnum;
297         struct dcesrv_mapiproxy_private         *private_data;
298
299
300         DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_pull\n"));
301
302         private_data = (struct dcesrv_mapiproxy_private *)dce_call->context->private_data;
303         table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
304         opnum = dce_call->pkt.u.request.opnum;
305
306         dce_call->fault_code = 0;
307
308         if (!NTLM_AUTH_IS_OK(dce_call)) {
309                 DEBUG(0, ("User is not authenticated, cannot process\n"));
310                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
311                 return NT_STATUS_NET_WRITE_FAULT;
312         }
313
314         /* If remote connection bind/auth has been delayed */
315         if (private_data->connected == false && private_data->server_mode == false) {
316                 status = mapiproxy_op_connect(dce_call, table, NULL);
317
318                 if (!NT_STATUS_IS_OK(status)) {
319                         dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
320                         return NT_STATUS_NET_WRITE_FAULT;
321                 }
322         }
323
324         if (opnum >= table->num_calls) {
325                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
326                 return NT_STATUS_NET_WRITE_FAULT;
327         }
328
329         *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
330         if (!*r) {
331                 return NT_STATUS_NO_MEMORY;
332         }
333
334         /* directly alter the pull struct before it got pulled from ndr */
335         mapiproxy_module_ndr_pull(dce_call, mem_ctx, pull);
336
337         ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
338
339         mapiproxy_module_pull(dce_call, mem_ctx, *r);
340
341         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
342                 DEBUG(0, ("mapiproxy: mapiproxy_ndr_pull: ERROR\n"));
343                 dcerpc_log_packet(dce_call->conn->packet_log_dir, table, opnum, NDR_IN, 
344                                   &dce_call->pkt.u.request.stub_and_verifier);
345                 dce_call->fault_code = DCERPC_FAULT_NDR;
346                 return NT_STATUS_NET_WRITE_FAULT;
347         }
348
349         return NT_STATUS_OK;
350 }
351
352
353 /**
354    \details This is the function called when mapiproxy receive a
355    response. The response has already been extracted and its
356    information filled into structures
357
358    \param dce_call pointer to the session context
359    \param mem_ctx pointer to the memory context
360    \param push pointer to the ndr_push structure
361    \param r generic pointer to the data pushed
362
363    \return NT_STATUS_OK on success, otherwise a NTSTATUS error
364  */
365 static NTSTATUS mapiproxy_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
366 {
367         struct dcesrv_mapiproxy_private         *private_data;
368         enum ndr_err_code                       ndr_err;
369         const struct ndr_interface_table        *table;
370         const struct ndr_interface_call         *call;
371         uint16_t                                opnum;
372         const char                              *name;
373
374         DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_push\n"));
375
376         private_data = (struct dcesrv_mapiproxy_private *)dce_call->context->private_data;
377         table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
378         opnum = dce_call->pkt.u.request.opnum;
379
380         name = table->calls[opnum].name;
381         call = &table->calls[opnum];
382
383         dce_call->fault_code = 0;
384
385         if (private_data->server_mode == false) {
386                 /* NspiGetProps binding strings replacement */
387                 if ((mapiproxy_server_loaded(NDR_EXCHANGE_NSP_NAME) == false) &&
388                     table->name && !strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) {
389                         switch (opnum) {
390                         case NDR_NSPIGETPROPS:
391                                 mapiproxy_NspiGetProps(dce_call, (struct NspiGetProps *)r);
392                                 break;
393                         case NDR_NSPIQUERYROWS:
394                                 mapiproxy_NspiQueryRows(dce_call, (struct NspiQueryRows *)r);
395                                 break;
396                         default:
397                                 break;
398                         }
399                 }
400
401                 /* RfrGetNewDSA FQDN replacement */
402                 if ((mapiproxy_server_loaded(NDR_EXCHANGE_DS_RFR_NAME) == false) &&
403                     table->name && !strcmp(table->name, NDR_EXCHANGE_DS_RFR_NAME)) {
404                         switch (opnum) {
405                         case NDR_RFRGETNEWDSA:
406                                 mapiproxy_RfrGetNewDSA(dce_call, (struct RfrGetNewDSA *)r);
407                                 break;
408                         default:
409                                 DEBUG(0, ("exchange_ds_rfr: OTHER DS-RFR CALL DETECTED!\n"));
410                                 break;
411                         }
412                 }
413         }
414
415         mapiproxy_module_push(dce_call, mem_ctx, (void *)r);
416
417         ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
418
419         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
420                 DEBUG(0, ("mapiproxy: mapiproxy_ndr_push: ERROR\n"));
421                 dce_call->fault_code = DCERPC_FAULT_NDR;
422                 return NT_STATUS_NET_WRITE_FAULT;
423         }
424
425         return NT_STATUS_OK;
426 }
427
428
429 /**
430    \details This function is called after the pull but before the
431    push. Moreover it is called before the request is forward to the
432    remote endpoint.
433
434    \param dce_call pointer to the session context
435    \param mem_ctx pointer to the memory context
436    \param r generic pointer to the call mapped data
437
438    \return NT_STATUS_OK on success, otherwise NTSTATUS error
439  */
440 static NTSTATUS mapiproxy_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
441 {
442         struct dcesrv_mapiproxy_private         *private_data;
443         struct ndr_push                         *push;
444         enum ndr_err_code                       ndr_err;
445         struct mapiproxy                        mapiproxy;
446         const struct ndr_interface_table        *table;
447         const struct ndr_interface_call         *call;
448         uint16_t                                opnum;
449         const char                              *name;
450         NTSTATUS                                status;
451
452         private_data = (struct dcesrv_mapiproxy_private *)dce_call->context->private_data;
453         table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
454         opnum = dce_call->pkt.u.request.opnum;
455
456         name = table->calls[opnum].name;
457         call = &table->calls[opnum];
458
459         mapiproxy.norelay = false;
460         mapiproxy.ahead = false;
461
462         if (!private_data) {
463                 dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
464                 return NT_STATUS_NET_WRITE_FAULT;
465         }
466
467         DEBUG(5, ("mapiproxy::mapiproxy_op_dispatch: %s(0x%x): %zd bytes\n",
468                   table->calls[opnum].name, opnum, table->calls[opnum].struct_size));
469
470         if (private_data->server_mode == false) {
471                 if (private_data->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
472                         ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);
473                 }
474
475                 private_data->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
476         }
477
478         if ((private_data->server_mode == true) || (mapiproxy_server_loaded(NDR_EXCHANGE_NSP_NAME) == true)) {
479                 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);
480                 status = mapiproxy_server_dispatch(dce_call, mem_ctx, r, &mapiproxy);
481                 ndr_print_function_debug(call->ndr_print, name, NDR_OUT | NDR_SET_VALUES, r);
482                 if (!NT_STATUS_IS_OK(status)) {
483                         return NT_STATUS_NET_WRITE_FAULT;
484                 }
485         } else {
486                 if (table->name && !strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) {
487                         if (opnum == NDR_NSPIDNTOMID) {
488                                 mapiproxy_NspiDNToMId(dce_call, (struct NspiDNToMId *)r);
489                         }
490                 }
491         }
492
493         if (private_data->server_mode == false) {
494         ahead:
495                 if (mapiproxy.ahead == true) {
496                         push = ndr_push_init_ctx(dce_call);
497                         NT_STATUS_HAVE_NO_MEMORY(push);
498                         ndr_err = call->ndr_push(push, NDR_OUT, r);
499                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
500                                 DEBUG(0, ("mapiproxy: mapiproxy_op_dispatch:push: ERROR\n"));
501                                 dce_call->fault_code = DCERPC_FAULT_NDR;
502                                 return NT_STATUS_NET_WRITE_FAULT;
503                         }
504                 }
505                 
506                 status = mapiproxy_module_dispatch(dce_call, mem_ctx, r, &mapiproxy);
507                 if (!NT_STATUS_IS_OK(status)) {
508                         private_data->c_pipe->last_fault_code = dce_call->fault_code;
509                         return NT_STATUS_NET_WRITE_FAULT;
510                 }
511                 
512                 private_data->c_pipe->last_fault_code = 0;
513                 if (mapiproxy.norelay == false) {
514                         status = dcerpc_binding_handle_call(private_data->c_pipe->binding_handle, NULL, table, opnum, mem_ctx, r);
515                 }
516                 
517                 dce_call->fault_code = private_data->c_pipe->last_fault_code;
518                 if (dce_call->fault_code != 0 || !NT_STATUS_IS_OK(status)) {
519                         DEBUG(0, ("mapiproxy: call[%s] failed with %s! (status = %s)\n", name, 
520                                   dcerpc_errstr(mem_ctx, dce_call->fault_code), nt_errstr(status)));
521                         return NT_STATUS_NET_WRITE_FAULT;
522                 }
523                 
524                 if ((dce_call->fault_code == 0) && 
525                     (private_data->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT) && mapiproxy.norelay == false) {
526                         ndr_print_function_debug(call->ndr_print, name, NDR_OUT | NDR_SET_VALUES, r);
527                 }
528                 
529                 if (mapiproxy.ahead == true) goto ahead;
530         }
531         
532         return NT_STATUS_OK;
533 }
534
535
536 /**
537    \details Register an endpoint
538
539    \param dce_ctx pointer to the dcerpc context
540    \param iface pointer to the dcesrv interface with function hooks
541
542    \return NT_STATUS_OK on success, otherwise NTSTATUS error
543  */
544 static NTSTATUS mapiproxy_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
545 {
546         const struct ndr_interface_table        *table = (const struct ndr_interface_table *) iface->private_data;
547         uint32_t                                i;
548
549         for (i = 0; i < table->endpoints->count; i++) {
550                 NTSTATUS        ret;
551                 const char      *name = table->endpoints->names[i];
552
553                 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
554                 if (!NT_STATUS_IS_OK(ret)) {
555                         DEBUG(1,("mapiproxy_op_init_server: failed to register endpoint '%s'\n", name));
556                         return ret;
557                 }
558         }
559
560         return NT_STATUS_OK;
561 }
562
563
564 /**
565    \details Initializes the server and register emsmdb,nspi and rfr
566    interfaces
567
568    \param dce_ctx pointer to the dcesrv context
569    \param ep_server pointer to the endpoint server list
570
571    \return NT_STATUS_OK on success, otherwise NTSTATUS error
572  */
573 static NTSTATUS mapiproxy_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
574 {
575         NTSTATUS                ret;
576         struct dcesrv_interface iface;
577         char                    **ifaces;
578         uint32_t                i;
579         static bool             initialized = false;
580
581         if (initialized == true) return NT_STATUS_OK;
582
583         /* Register mapiproxy modules */
584         ret = mapiproxy_module_init(dce_ctx);
585         NT_STATUS_NOT_OK_RETURN(ret);
586
587         /* Register mapiproxy servers */
588         ret = mapiproxy_server_init(dce_ctx);
589         NT_STATUS_NOT_OK_RETURN(ret);
590
591         ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "interfaces"), NULL);
592
593         for (i = 0; ifaces[i]; i++) {
594                 /* Register the interface */
595                 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
596                         DEBUG(0, ("mapiproxy_op_init_server: failed to find interface '%s'\n", ifaces[i]));
597                         return NT_STATUS_UNSUCCESSFUL;
598                 }
599
600                 ret = mapiproxy_register_one_iface(dce_ctx, &iface);
601                 if (!NT_STATUS_IS_OK(ret)) {
602                         DEBUG(0, ("mapiproxy_op_init_server: failed to register interface '%s'\n", ifaces[i]));
603                         return ret;
604                 }
605         }
606
607         initialized = true;
608         return NT_STATUS_OK;
609 }
610
611
612 static bool mapiproxy_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *tbl)
613 {
614         iface->name = tbl->name;
615         iface->syntax_id = tbl->syntax_id;
616         
617         iface->bind = mapiproxy_op_bind;
618         iface->unbind = mapiproxy_op_unbind;
619         
620         iface->ndr_pull = mapiproxy_op_ndr_pull;
621         iface->dispatch = mapiproxy_op_dispatch;
622         iface->reply = mapiproxy_op_reply;
623         iface->ndr_push = mapiproxy_op_ndr_push;
624
625         iface->private_data = tbl;
626
627         return true;
628 }
629
630
631 static bool mapiproxy_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
632 {
633         const struct ndr_interface_list *l;
634
635         for (l = ndr_table_list(); l; l = l->next) {
636                 if (l->table->syntax_id.if_version == if_version &&
637                     GUID_equal(&l->table->syntax_id.uuid, uuid) == 0) {
638                         return mapiproxy_fill_interface(iface, l->table);
639                 }
640         }
641
642         return false;
643 }
644
645
646 static bool mapiproxy_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
647 {
648         const struct ndr_interface_table        *tbl;
649
650         tbl = ndr_table_by_name(name);
651
652         if (tbl) {
653                 return mapiproxy_fill_interface(iface, tbl);
654         }
655
656         return false;
657 }
658
659
660 /**
661    \details register the mapiproxy endpoint server.
662
663    \return NT_STATUS_OK on success, otherwise NTSTATUS error
664  */
665 NTSTATUS dcerpc_server_mapiproxy_init(void)
666 {
667         NTSTATUS                        ret;
668         struct dcesrv_endpoint_server   ep_server;
669
670         ZERO_STRUCT(ep_server);
671
672         /* Fill in our name */
673         ep_server.name = "mapiproxy";
674
675         /* Fill in all the operations */
676         ep_server.init_server = mapiproxy_op_init_server;
677
678         ep_server.interface_by_uuid = mapiproxy_op_interface_by_uuid;
679         ep_server.interface_by_name = mapiproxy_op_interface_by_name;
680
681         /* Register ourselves with the DCE/RPC subsystem */
682         ret = dcerpc_register_ep_server(&ep_server);
683         if (!NT_STATUS_IS_OK(ret)) {
684                 DEBUG(0, ("Failed to register 'mapiproxy' endpoint server!"));
685                 return ret;
686         }
687
688         /* Full DCE/RPC interface table needed */
689         ndr_table_init();
690         
691         return ret;
692 }
693
694 /**
695    \details Register mapiproxy dynamic shared object modules
696
697    This function registers mapiproxy modules located
698  */
699
700 /**
701    \details Entry point of mapiproxy dynamic shared object.
702
703    This function first registers exchange endpoints and ndr tables,
704    then attempts to register the mapiproxy interface.
705
706    \return NT_STATUS_OK on success, otherwise NT_STATUS_UNSUCCESSFUL;
707  */
708 NTSTATUS samba_init_module(void)
709 {
710         NTSTATUS status;
711
712         /* Step1. Register Exchange endpoints */
713         status = dcerpc_server_exchange_emsmdb_init();
714         NT_STATUS_NOT_OK_RETURN(status);
715
716         status = dcerpc_server_exchange_nsp_init();
717         NT_STATUS_NOT_OK_RETURN(status);
718
719         status = dcerpc_server_exchange_ds_rfr_init();
720         NT_STATUS_NOT_OK_RETURN(status);
721
722         /* Step2. Register Exchange ndr tables */
723         status = ndr_table_register(&ndr_table_exchange_emsmdb);
724         NT_STATUS_NOT_OK_RETURN(status);
725
726         status = ndr_table_register(&ndr_table_exchange_nsp);
727         NT_STATUS_NOT_OK_RETURN(status);
728
729         status = ndr_table_register(&ndr_table_exchange_ds_rfr);
730         NT_STATUS_NOT_OK_RETURN(status);
731
732         /* Step3. Finally register mapiproxy endpoint */
733         status = dcerpc_server_mapiproxy_init();
734         NT_STATUS_NOT_OK_RETURN(status);
735
736         return NT_STATUS_OK;
737 }
738
739 /* include server boiler template */
740 #include "gen_ndr/ndr_exchange_s.c"