4 This proxy is based on dcesrv_remote.c code from Stefan Metzemacher
8 Copyright (C) Julien Kerihuel 2008-2010
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.
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.
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/>.
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>
31 static int dispatch_nbr = 0;
34 \file dcesrv_mapiproxy.c
36 \brief mapiproxy main file
40 static NTSTATUS mapiproxy_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
42 DEBUG(5, ("mapiproxy::mapiproxy_op_reply\n"));
46 static NTSTATUS mapiproxy_op_connect(struct dcesrv_call_state *dce_call,
47 const struct ndr_interface_table *table,
51 struct dcesrv_mapiproxy_private *private;
55 struct cli_credentials *credentials;
56 bool acquired_creds = false;
59 DEBUG(5, ("mapiproxy::mapiproxy_op_connect\n"));
61 /* Retrieve the binding string from parametric options if undefined */
63 binding = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "binding");
65 DEBUG(0, ("You must specify a DCE/RPC binding string\n"));
66 return NT_STATUS_INVALID_PARAMETER;
70 /* Retrieve parametric options */
71 machine_account = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "use_machine_account", false);
72 user = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "username");
73 pass = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "password");
74 domain = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "domain");
76 /* Retrieve private mapiproxy data */
77 private = dce_call->context->private_data;
80 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using specified account\n"));
81 credentials = cli_credentials_init(private);
83 return NT_STATUS_NO_MEMORY;
86 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
87 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
89 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
91 cli_credentials_set_password(credentials, pass, CRED_SPECIFIED);
92 } else if (machine_account) {
93 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using machine account\n"));
94 credentials = cli_credentials_init(private);
96 return NT_STATUS_NO_MEMORY;
98 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
100 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
102 status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
103 if (!NT_STATUS_IS_OK(status)) {
106 } else if (dcesrv_call_credentials(dce_call)) {
107 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using delegated credentials\n"));
108 credentials = dcesrv_call_credentials(dce_call);
109 acquired_creds = true;
110 } else if (private->credentials) {
111 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using acquired deletegated credentials\n"));
112 credentials = private->credentials;
113 acquired_creds = true;
115 DEBUG(1, ("dcerpc_mapiproxy: RPC proxy: You must supply binding, user and password or have delegated credentials\n"));
116 return NT_STATUS_INVALID_PARAMETER;
119 if (((dce_call->pkt.ptype == DCERPC_PKT_BIND) && dce_call->pkt.u.bind.assoc_group_id) ||
120 ((dce_call->pkt.ptype == DCERPC_PKT_ALTER) && dce_call->pkt.u.alter.assoc_group_id)) {
121 struct dcerpc_binding *b;
122 struct composite_context *pipe_conn_req;
124 /* parse binding string to the structure */
125 status = dcerpc_parse_binding(dce_call->context, binding, &b);
126 if (!NT_STATUS_IS_OK(status)) {
127 DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", binding));
131 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
133 switch (dce_call->pkt.ptype) {
134 case DCERPC_PKT_BIND:
135 b->assoc_group_id = dce_call->pkt.u.bind.assoc_group_id;
137 case DCERPC_PKT_ALTER:
138 b->assoc_group_id = dce_call->pkt.u.alter.assoc_group_id;
144 pipe_conn_req = dcerpc_pipe_connect_b_send(dce_call->context, b, table,
145 credentials, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx);
146 status = dcerpc_pipe_connect_b_recv(pipe_conn_req, dce_call->context, &(private->c_pipe));
148 if (acquired_creds == false) {
149 talloc_free(credentials);
152 if (!NT_STATUS_IS_OK(status)) {
155 dce_call->context->assoc_group->id = private->c_pipe->assoc_group_id;
158 status = dcerpc_pipe_connect(dce_call->context,
159 &(private->c_pipe), binding, table,
160 credentials, dce_call->event_ctx,
161 dce_call->conn->dce_ctx->lp_ctx);
163 if (acquired_creds == false) {
164 talloc_free(credentials);
167 if (!NT_STATUS_IS_OK(status)) {
170 dce_call->context->assoc_group->id = private->c_pipe->assoc_group_id;
173 private->connected = true;
175 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: CONNECTED\n"));
180 static NTSTATUS mapiproxy_op_bind_proxy(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
182 NTSTATUS status = NT_STATUS_OK;
183 const struct ndr_interface_table *table;
184 struct dcesrv_mapiproxy_private *private;
187 /* Retrieve private mapiproxy data */
188 private = dce_call->context->private_data;
190 table = ndr_table_by_uuid(&iface->syntax_id.uuid);
192 dce_call->fault_code = DCERPC_FAULT_UNK_IF;
193 return NT_STATUS_NET_WRITE_FAULT;
196 if (dcesrv_call_credentials(dce_call)) {
197 private->credentials = dcesrv_call_credentials(dce_call);
198 DEBUG(5, ("dcerpc_mapiproxy: Delegated credentials acquired\n"));
201 delegated = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "delegated_auth", false);
202 if (delegated == false) {
203 status = mapiproxy_op_connect(dce_call, table, NULL);
211 \details This function is called when the client binds to one of
212 the interfaces mapiproxy handles.
214 \param dce_call pointer to the session context
215 \param iface pointer to the dcesrv interface structure with
217 \param if_version the version of the pipe
219 \return NT_STATUS_OK on success, otherwise NTSTATUS error
221 static NTSTATUS mapiproxy_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
223 struct dcesrv_mapiproxy_private *private;
225 char *server_id_printable = NULL;
227 server_id_printable = server_id_str(NULL, &(dce_call->conn->server_id));
228 DEBUG(5, ("mapiproxy::%s: [session = 0x%x] [session server id = %s]\n",
229 __FUNCTION__, dce_call->context->context_id,
230 server_id_printable));
231 talloc_free(server_id_printable);
233 DEBUG(5, ("mapiproxy::mapiproxy_op_bind: [session = 0x%x] [session server id = 0x%"PRIx64" 0x%x 0x%x]\n", dce_call->context->context_id,
234 dce_call->conn->server_id.pid, dce_call->conn->server_id.task_id, dce_call->conn->server_id.vnn));
236 /* Retrieve server mode parametric option */
237 server_mode = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "server", false);
239 /* Initialize private structure */
240 private = talloc(dce_call->context, struct dcesrv_mapiproxy_private);
242 return NT_STATUS_NO_MEMORY;
245 private->c_pipe = NULL;
246 private->exchname = NULL;
247 private->server_mode = server_mode;
248 private->connected = false;
250 dce_call->context->private_data = private;
252 if (server_mode == false) {
253 return mapiproxy_op_bind_proxy(dce_call, iface, if_version);
261 \details Called when the client disconnects from one of the
262 endpoints managed by mapiproxy.
264 \param context pointer to the connection context
265 \param iface pointer to the dcesrv interface structure with
268 static void mapiproxy_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
270 struct dcesrv_mapiproxy_private *private = (struct dcesrv_mapiproxy_private *) context->private_data;
272 DEBUG(5, ("mapiproxy::mapiproxy_op_unbind\n"));
274 mapiproxy_module_unbind(context->conn->server_id, context->context_id);
275 mapiproxy_server_unbind(context->conn->server_id, context->context_id);
278 talloc_free(private->c_pipe);
279 talloc_free(private);
282 talloc_free(context);
289 \details This is the function called when mapiproxy receives a
290 request. The request has already been extracted and its information
291 filled into structures
293 \param dce_call pointer to the session context
294 \param mem_ctx pointer to the memory context
295 \param pull pointer on pointer to the ndr_pull structure
296 \param r generic pointer on pointer to the pulled ndr content
298 \return NT_STATUS_OK on success, other NTSTATUS error
300 static NTSTATUS mapiproxy_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
303 enum ndr_err_code ndr_err;
304 const struct ndr_interface_table *table;
306 struct dcesrv_mapiproxy_private *private;
309 DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_pull\n"));
311 private = dce_call->context->private_data;
312 table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
313 opnum = dce_call->pkt.u.request.opnum;
315 dce_call->fault_code = 0;
317 if (!dcesrv_call_authenticated(dce_call)) {
318 DEBUG(0, ("User is not authenticated, cannot process\n"));
319 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
320 return NT_STATUS_NET_WRITE_FAULT;
323 /* If remote connection bind/auth has been delayed */
324 if (private->connected == false && private->server_mode == false) {
325 status = mapiproxy_op_connect(dce_call, table, NULL);
327 if (!NT_STATUS_IS_OK(status)) {
328 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
329 return NT_STATUS_NET_WRITE_FAULT;
333 if (opnum >= table->num_calls) {
334 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
335 return NT_STATUS_NET_WRITE_FAULT;
338 *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
340 return NT_STATUS_NO_MEMORY;
343 /* directly alter the pull struct before it got pulled from ndr */
344 mapiproxy_module_ndr_pull(dce_call, mem_ctx, pull);
346 ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
348 mapiproxy_module_pull(dce_call, mem_ctx, *r);
350 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
351 DEBUG(0, ("mapiproxy: mapiproxy_ndr_pull: ERROR\n"));
352 dcerpc_log_packet(dce_call->conn->packet_log_dir, table, opnum, NDR_IN,
353 &dce_call->pkt.u.request.stub_and_verifier);
354 dce_call->fault_code = DCERPC_FAULT_NDR;
355 return NT_STATUS_NET_WRITE_FAULT;
363 \details This is the function called when mapiproxy receive a
364 response. The response has already been extracted and its
365 information filled into structures
367 \param dce_call pointer to the session context
368 \param mem_ctx pointer to the memory context
369 \param push pointer to the ndr_push structure
370 \param r generic pointer to the data pushed
372 \return NT_STATUS_OK on success, otherwise a NTSTATUS error
374 static NTSTATUS mapiproxy_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
376 struct dcesrv_mapiproxy_private *private;
377 enum ndr_err_code ndr_err;
378 const struct ndr_interface_table *table;
379 /* const struct ndr_interface_call *call; */
381 /* const char *name; */
383 DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_push\n"));
385 private = dce_call->context->private_data;
386 table = (const struct ndr_interface_table *)dce_call->context->iface->private_data;
387 opnum = dce_call->pkt.u.request.opnum;
389 /* name = table->calls[opnum].name; */
390 /* call = &table->calls[opnum]; */
392 dce_call->fault_code = 0;
394 if (private->server_mode == false) {
395 /* NspiGetProps binding strings replacement */
396 if ((mapiproxy_server_loaded(NDR_EXCHANGE_NSP_NAME) == false) &&
397 table->name && !strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) {
399 case NDR_NSPIGETPROPS:
400 mapiproxy_NspiGetProps(dce_call, (struct NspiGetProps *)r);
402 case NDR_NSPIQUERYROWS:
403 mapiproxy_NspiQueryRows(dce_call, (struct NspiQueryRows *)r);
410 /* RfrGetNewDSA FQDN replacement */
411 if ((mapiproxy_server_loaded(NDR_EXCHANGE_DS_RFR_NAME) == false) &&
412 table->name && !strcmp(table->name, NDR_EXCHANGE_DS_RFR_NAME)) {
414 case NDR_RFRGETNEWDSA:
415 mapiproxy_RfrGetNewDSA(dce_call, (struct RfrGetNewDSA *)r);
418 DEBUG(0, ("exchange_ds_rfr: OTHER DS-RFR CALL DETECTED!\n"));
424 mapiproxy_module_push(dce_call, mem_ctx, (void *)r);
426 ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
428 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
429 DEBUG(0, ("mapiproxy: mapiproxy_ndr_push: ERROR\n"));
430 dce_call->fault_code = DCERPC_FAULT_NDR;
431 return NT_STATUS_NET_WRITE_FAULT;
439 \details This function is called after the pull but before the
440 push. Moreover it is called before the request is forward to the
443 \param dce_call pointer to the session context
444 \param mem_ctx pointer to the memory context
445 \param r generic pointer to the call mapped data
447 \return NT_STATUS_OK on success, otherwise NTSTATUS error
449 static NTSTATUS mapiproxy_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
451 struct dcesrv_mapiproxy_private *private;
452 struct ndr_push *push;
453 enum ndr_err_code ndr_err;
454 struct mapiproxy mapiproxy;
455 const struct ndr_interface_table *table;
456 const struct ndr_interface_call *call;
463 this_dispatch = dispatch_nbr;
466 gettimeofday(&tv, NULL);
467 DEBUG(5, ("mapiproxy::mapiproxy_op_dispatch: [tv=%lu.%.6lu] [#%d start]\n", tv.tv_sec, tv.tv_usec, this_dispatch));
469 private = dce_call->context->private_data;
470 table = dce_call->context->iface->private_data;
471 opnum = dce_call->pkt.u.request.opnum;
473 name = table->calls[opnum].name;
474 call = &table->calls[opnum];
476 mapiproxy.norelay = false;
477 mapiproxy.ahead = false;
480 dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
481 return NT_STATUS_NET_WRITE_FAULT;
484 DEBUG(5, ("mapiproxy::mapiproxy_op_dispatch: %s(0x%x): %zd bytes\n",
485 table->calls[opnum].name, opnum, table->calls[opnum].struct_size));
487 if (private->server_mode == false) {
488 if (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_IN) {
489 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);
492 private->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
495 if ((private->server_mode == true) || (mapiproxy_server_loaded(NDR_EXCHANGE_NSP_NAME) == true)) {
496 ndr_print_function_debug(call->ndr_print, name, NDR_IN | NDR_SET_VALUES, r);
497 status = mapiproxy_server_dispatch(dce_call, mem_ctx, r, &mapiproxy);
498 ndr_print_function_debug(call->ndr_print, name, NDR_OUT | NDR_SET_VALUES, r);
499 if (!NT_STATUS_IS_OK(status)) {
500 return NT_STATUS_NET_WRITE_FAULT;
503 if (table->name && !strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) {
504 if (opnum == NDR_NSPIDNTOMID) {
505 mapiproxy_NspiDNToMId(dce_call, (struct NspiDNToMId *)r);
510 if (private->server_mode == false) {
512 if (mapiproxy.ahead == true) {
513 push = ndr_push_init_ctx(dce_call);
514 NT_STATUS_HAVE_NO_MEMORY(push);
515 ndr_err = call->ndr_push(push, NDR_OUT, r);
516 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
517 DEBUG(0, ("mapiproxy: mapiproxy_op_dispatch:push: ERROR\n"));
518 dce_call->fault_code = DCERPC_FAULT_NDR;
519 return NT_STATUS_NET_WRITE_FAULT;
523 status = mapiproxy_module_dispatch(dce_call, mem_ctx, r, &mapiproxy);
524 if (!NT_STATUS_IS_OK(status)) {
525 private->c_pipe->last_fault_code = dce_call->fault_code;
526 return NT_STATUS_NET_WRITE_FAULT;
529 private->c_pipe->last_fault_code = 0;
530 if (mapiproxy.norelay == false) {
531 status = dcerpc_binding_handle_call(private->c_pipe->binding_handle, NULL, table, opnum, mem_ctx, r);
534 dce_call->fault_code = private->c_pipe->last_fault_code;
535 if (dce_call->fault_code != 0 || !NT_STATUS_IS_OK(status)) {
536 DEBUG(0, ("mapiproxy: call[%s] failed with %s! (status = %s)\n", name,
537 dcerpc_errstr(mem_ctx, dce_call->fault_code), nt_errstr(status)));
538 return NT_STATUS_NET_WRITE_FAULT;
541 if ((dce_call->fault_code == 0) &&
542 (private->c_pipe->conn->flags & DCERPC_DEBUG_PRINT_OUT) && mapiproxy.norelay == false) {
543 ndr_print_function_debug(call->ndr_print, name, NDR_OUT | NDR_SET_VALUES, r);
546 if (mapiproxy.ahead == true) goto ahead;
549 gettimeofday(&tv, NULL);
550 DEBUG(5, ("mapiproxy::mapiproxy_op_dispatch: [tv=%lu.%.6lu] [#%d end]\n", tv.tv_sec, tv.tv_usec, this_dispatch));
557 \details Register an endpoint
559 \param dce_ctx pointer to the dcerpc context
560 \param iface pointer to the dcesrv interface with function hooks
562 \return NT_STATUS_OK on success, otherwise NTSTATUS error
564 static NTSTATUS mapiproxy_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
566 const struct ndr_interface_table *table = iface->private_data;
569 for (i = 0; i < table->endpoints->count; i++) {
571 const char *name = table->endpoints->names[i];
573 ret = dcesrv_interface_register(dce_ctx, name, iface, NULL);
574 if (!NT_STATUS_IS_OK(ret)) {
575 DEBUG(1,("mapiproxy_op_init_server: failed to register endpoint '%s'\n", name));
585 \details Initializes the server and register emsmdb,nspi and rfr
588 \param dce_ctx pointer to the dcesrv context
589 \param ep_server pointer to the endpoint server list
591 \return NT_STATUS_OK on success, otherwise NTSTATUS error
593 static NTSTATUS mapiproxy_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
596 struct dcesrv_interface iface;
599 static bool initialized = false;
601 if (initialized == true) return NT_STATUS_OK;
603 /* Register mapiproxy modules */
604 ret = mapiproxy_module_init(dce_ctx);
605 NT_STATUS_NOT_OK_RETURN(ret);
607 /* Register mapiproxy servers */
608 ret = mapiproxy_server_init(dce_ctx);
609 NT_STATUS_NOT_OK_RETURN(ret);
611 ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "interfaces"), NULL);
613 for (i = 0; ifaces[i]; i++) {
614 /* Register the interface */
615 if (!ep_server->interface_by_name(&iface, ifaces[i])) {
616 DEBUG(0, ("mapiproxy_op_init_server: failed to find interface '%s'\n", ifaces[i]));
617 return NT_STATUS_UNSUCCESSFUL;
620 ret = mapiproxy_register_one_iface(dce_ctx, &iface);
621 if (!NT_STATUS_IS_OK(ret)) {
622 DEBUG(0, ("mapiproxy_op_init_server: failed to register interface '%s'\n", ifaces[i]));
632 static bool mapiproxy_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *tbl)
634 iface->name = tbl->name;
635 iface->syntax_id = tbl->syntax_id;
637 iface->bind = mapiproxy_op_bind;
638 iface->unbind = mapiproxy_op_unbind;
640 iface->ndr_pull = mapiproxy_op_ndr_pull;
641 iface->dispatch = mapiproxy_op_dispatch;
642 iface->reply = mapiproxy_op_reply;
643 iface->ndr_push = mapiproxy_op_ndr_push;
645 iface->private_data = tbl;
651 static bool mapiproxy_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
653 const struct ndr_interface_list *l;
655 for (l = ndr_table_list(); l; l = l->next) {
656 if (l->table->syntax_id.if_version == if_version &&
657 GUID_equal(&l->table->syntax_id.uuid, uuid) == 0) {
658 return mapiproxy_fill_interface(iface, l->table);
666 static bool mapiproxy_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
668 const struct ndr_interface_table *tbl;
670 tbl = ndr_table_by_name(name);
673 return mapiproxy_fill_interface(iface, tbl);
681 \details register the mapiproxy endpoint server.
683 \return NT_STATUS_OK on success, otherwise NTSTATUS error
685 NTSTATUS dcerpc_server_mapiproxy_init(void)
688 struct dcesrv_endpoint_server ep_server;
690 ZERO_STRUCT(ep_server);
692 /* Fill in our name */
693 ep_server.name = "mapiproxy";
695 /* Fill in all the operations */
696 ep_server.init_server = mapiproxy_op_init_server;
698 ep_server.interface_by_uuid = mapiproxy_op_interface_by_uuid;
699 ep_server.interface_by_name = mapiproxy_op_interface_by_name;
701 /* Register ourselves with the DCE/RPC subsystem */
702 ret = dcerpc_register_ep_server(&ep_server);
703 if (!NT_STATUS_IS_OK(ret)) {
704 DEBUG(0, ("Failed to register 'mapiproxy' endpoint server!"));
708 /* Full DCE/RPC interface table needed */
715 \details Register mapiproxy dynamic shared object modules
717 This function registers mapiproxy modules located
721 \details Entry point of mapiproxy dynamic shared object.
723 This function first registers exchange endpoints and ndr tables,
724 then attempts to register the mapiproxy interface.
726 \return NT_STATUS_OK on success, otherwise NT_STATUS_UNSUCCESSFUL;
728 NTSTATUS samba_init_module(void)
732 /* Step1. Register Exchange endpoints */
733 status = dcerpc_server_exchange_emsmdb_init();
734 NT_STATUS_NOT_OK_RETURN(status);
736 status = dcerpc_server_exchange_nsp_init();
737 NT_STATUS_NOT_OK_RETURN(status);
739 status = dcerpc_server_exchange_ds_rfr_init();
740 NT_STATUS_NOT_OK_RETURN(status);
742 /* Step2. Register Exchange ndr tables */
743 status = ndr_table_register(&ndr_table_exchange_emsmdb);
744 NT_STATUS_NOT_OK_RETURN(status);
746 status = ndr_table_register(&ndr_table_exchange_nsp);
747 NT_STATUS_NOT_OK_RETURN(status);
749 status = ndr_table_register(&ndr_table_exchange_ds_rfr);
750 NT_STATUS_NOT_OK_RETURN(status);
752 /* Step3. Finally register mapiproxy endpoint */
753 status = dcerpc_server_mapiproxy_init();
754 NT_STATUS_NOT_OK_RETURN(status);
759 /* include server boiler template */
760 #include "gen_ndr/ndr_exchange_s.c"