4 This proxy is based on dcesrv_remote.c code from Stefan Metzemacher
8 Copyright (C) Julien Kerihuel 2008-2011
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>
32 \file dcesrv_mapiproxy.c
34 \brief mapiproxy main file
38 static NTSTATUS mapiproxy_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
40 DEBUG(5, ("mapiproxy::mapiproxy_op_reply\n"));
44 static NTSTATUS mapiproxy_op_connect(struct dcesrv_call_state *dce_call,
45 const struct ndr_interface_table *table,
49 struct dcesrv_mapiproxy_private *private_data;
53 struct cli_credentials *credentials;
54 bool acquired_creds = false;
57 DEBUG(5, ("mapiproxy::mapiproxy_op_connect\n"));
59 /* Retrieve the binding string from parametric options if undefined */
61 binding = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "binding");
63 DEBUG(0, ("You must specify a DCE/RPC binding string\n"));
64 return NT_STATUS_INVALID_PARAMETER;
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");
74 /* Retrieve private mapiproxy data */
75 private_data = (struct dcesrv_mapiproxy_private *) dce_call->context->private_data;
78 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using specified account\n"));
79 credentials = cli_credentials_init(private_data);
81 return NT_STATUS_NO_MEMORY;
84 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
85 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
87 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
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);
94 return NT_STATUS_NO_MEMORY;
96 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
98 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
100 status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
101 if (!NT_STATUS_IS_OK(status)) {
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;
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;
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;
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));
129 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
131 switch (dce_call->pkt.ptype) {
132 case DCERPC_PKT_BIND:
133 b->assoc_group_id = dce_call->pkt.u.bind.assoc_group_id;
135 case DCERPC_PKT_ALTER:
136 b->assoc_group_id = dce_call->pkt.u.alter.assoc_group_id;
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));
146 if (acquired_creds == false) {
147 talloc_free(credentials);
150 if (!NT_STATUS_IS_OK(status)) {
153 dce_call->context->assoc_group->id = private_data->c_pipe->assoc_group_id;
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);
161 if (acquired_creds == false) {
162 talloc_free(credentials);
165 if (!NT_STATUS_IS_OK(status)) {
168 dce_call->context->assoc_group->id = private_data->c_pipe->assoc_group_id;
171 private_data->connected = true;
173 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: CONNECTED\n"));
178 static NTSTATUS mapiproxy_op_bind_proxy(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
180 NTSTATUS status = NT_STATUS_OK;
181 const struct ndr_interface_table *table;
182 struct dcesrv_mapiproxy_private *private_data;
185 /* Retrieve private mapiproxy data */
186 private_data = (struct dcesrv_mapiproxy_private *)dce_call->context->private_data;
188 table = ndr_table_by_uuid(&iface->syntax_id.uuid);
190 dce_call->fault_code = DCERPC_FAULT_UNK_IF;
191 return NT_STATUS_NET_WRITE_FAULT;
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"));
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);
209 \details This function is called when the client binds to one of
210 the interfaces mapiproxy handles.
212 \param dce_call pointer to the session context
213 \param iface pointer to the dcesrv interface structure with
215 \param if_version the version of the pipe
217 \return NT_STATUS_OK on success, otherwise NTSTATUS error
219 static NTSTATUS mapiproxy_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
221 struct dcesrv_mapiproxy_private *private_data;
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));
227 /* Retrieve server mode parametric option */
228 server_mode = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "server", false);
230 /* Initialize private structure */
231 private_data = talloc(dce_call->context, struct dcesrv_mapiproxy_private);
233 return NT_STATUS_NO_MEMORY;
236 private_data->c_pipe = NULL;
237 private_data->exchname = NULL;
238 private_data->server_mode = server_mode;
239 private_data->connected = false;
241 dce_call->context->private_data = private_data;
243 if (server_mode == false) {
244 return mapiproxy_op_bind_proxy(dce_call, iface, if_version);
252 \details Called when the client disconnects from one of the
253 endpoints managed by mapiproxy.
255 \param context pointer to the connection context
256 \param iface pointer to the dcesrv interface structure with
259 static void mapiproxy_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
261 struct dcesrv_mapiproxy_private *private_data = (struct dcesrv_mapiproxy_private *) context->private_data;
263 DEBUG(5, ("mapiproxy::mapiproxy_op_unbind\n"));
265 mapiproxy_module_unbind(context->conn->server_id, context->context_id);
266 mapiproxy_server_unbind(context->conn->server_id, context->context_id);
269 talloc_free(private_data->c_pipe);
270 talloc_free(private_data);
273 talloc_free(context);
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
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
289 \return NT_STATUS_OK on success, other NTSTATUS error
291 static NTSTATUS mapiproxy_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
294 enum ndr_err_code ndr_err;
295 const struct ndr_interface_table *table;
297 struct dcesrv_mapiproxy_private *private_data;
300 DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_pull\n"));
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;
306 dce_call->fault_code = 0;
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;
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);
318 if (!NT_STATUS_IS_OK(status)) {
319 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
320 return NT_STATUS_NET_WRITE_FAULT;
324 if (opnum >= table->num_calls) {
325 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
326 return NT_STATUS_NET_WRITE_FAULT;
329 *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
331 return NT_STATUS_NO_MEMORY;
334 /* directly alter the pull struct before it got pulled from ndr */
335 mapiproxy_module_ndr_pull(dce_call, mem_ctx, pull);
337 ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
339 mapiproxy_module_pull(dce_call, mem_ctx, *r);
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;
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
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
363 \return NT_STATUS_OK on success, otherwise a NTSTATUS error
365 static NTSTATUS mapiproxy_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
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;
374 DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_push\n"));
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;
380 name = table->calls[opnum].name;
381 call = &table->calls[opnum];
383 dce_call->fault_code = 0;
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)) {
390 case NDR_NSPIGETPROPS:
391 mapiproxy_NspiGetProps(dce_call, (struct NspiGetProps *)r);
393 case NDR_NSPIQUERYROWS:
394 mapiproxy_NspiQueryRows(dce_call, (struct NspiQueryRows *)r);
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)) {
405 case NDR_RFRGETNEWDSA:
406 mapiproxy_RfrGetNewDSA(dce_call, (struct RfrGetNewDSA *)r);
409 DEBUG(0, ("exchange_ds_rfr: OTHER DS-RFR CALL DETECTED!\n"));
415 mapiproxy_module_push(dce_call, mem_ctx, (void *)r);
417 ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
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;
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
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
438 \return NT_STATUS_OK on success, otherwise NTSTATUS error
440 static NTSTATUS mapiproxy_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
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;
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;
456 name = table->calls[opnum].name;
457 call = &table->calls[opnum];
459 mapiproxy.norelay = false;
460 mapiproxy.ahead = false;
463 dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
464 return NT_STATUS_NET_WRITE_FAULT;
467 DEBUG(5, ("mapiproxy::mapiproxy_op_dispatch: %s(0x%x): %zd bytes\n",
468 table->calls[opnum].name, opnum, table->calls[opnum].struct_size));
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);
475 private_data->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
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;
486 if (table->name && !strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) {
487 if (opnum == NDR_NSPIDNTOMID) {
488 mapiproxy_NspiDNToMId(dce_call, (struct NspiDNToMId *)r);
493 if (private_data->server_mode == false) {
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;
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;
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);
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;
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);
529 if (mapiproxy.ahead == true) goto ahead;
537 \details Register an endpoint
539 \param dce_ctx pointer to the dcerpc context
540 \param iface pointer to the dcesrv interface with function hooks
542 \return NT_STATUS_OK on success, otherwise NTSTATUS error
544 static NTSTATUS mapiproxy_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
546 const struct ndr_interface_table *table = (const struct ndr_interface_table *) iface->private_data;
549 for (i = 0; i < table->endpoints->count; i++) {
551 const char *name = table->endpoints->names[i];
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));
565 \details Initializes the server and register emsmdb,nspi and rfr
568 \param dce_ctx pointer to the dcesrv context
569 \param ep_server pointer to the endpoint server list
571 \return NT_STATUS_OK on success, otherwise NTSTATUS error
573 static NTSTATUS mapiproxy_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
576 struct dcesrv_interface iface;
579 static bool initialized = false;
581 if (initialized == true) return NT_STATUS_OK;
583 /* Register mapiproxy modules */
584 ret = mapiproxy_module_init(dce_ctx);
585 NT_STATUS_NOT_OK_RETURN(ret);
587 /* Register mapiproxy servers */
588 ret = mapiproxy_server_init(dce_ctx);
589 NT_STATUS_NOT_OK_RETURN(ret);
591 ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "interfaces"), NULL);
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;
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]));
612 static bool mapiproxy_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *tbl)
614 iface->name = tbl->name;
615 iface->syntax_id = tbl->syntax_id;
617 iface->bind = mapiproxy_op_bind;
618 iface->unbind = mapiproxy_op_unbind;
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;
625 iface->private_data = tbl;
631 static bool mapiproxy_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
633 const struct ndr_interface_list *l;
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);
646 static bool mapiproxy_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
648 const struct ndr_interface_table *tbl;
650 tbl = ndr_table_by_name(name);
653 return mapiproxy_fill_interface(iface, tbl);
661 \details register the mapiproxy endpoint server.
663 \return NT_STATUS_OK on success, otherwise NTSTATUS error
665 NTSTATUS dcerpc_server_mapiproxy_init(void)
668 struct dcesrv_endpoint_server ep_server;
670 ZERO_STRUCT(ep_server);
672 /* Fill in our name */
673 ep_server.name = "mapiproxy";
675 /* Fill in all the operations */
676 ep_server.init_server = mapiproxy_op_init_server;
678 ep_server.interface_by_uuid = mapiproxy_op_interface_by_uuid;
679 ep_server.interface_by_name = mapiproxy_op_interface_by_name;
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!"));
688 /* Full DCE/RPC interface table needed */
695 \details Register mapiproxy dynamic shared object modules
697 This function registers mapiproxy modules located
701 \details Entry point of mapiproxy dynamic shared object.
703 This function first registers exchange endpoints and ndr tables,
704 then attempts to register the mapiproxy interface.
706 \return NT_STATUS_OK on success, otherwise NT_STATUS_UNSUCCESSFUL;
708 NTSTATUS samba_init_module(void)
712 /* Step1. Register Exchange endpoints */
713 status = dcerpc_server_exchange_emsmdb_init();
714 NT_STATUS_NOT_OK_RETURN(status);
716 status = dcerpc_server_exchange_nsp_init();
717 NT_STATUS_NOT_OK_RETURN(status);
719 status = dcerpc_server_exchange_ds_rfr_init();
720 NT_STATUS_NOT_OK_RETURN(status);
722 /* Step2. Register Exchange ndr tables */
723 status = ndr_table_register(&ndr_table_exchange_emsmdb);
724 NT_STATUS_NOT_OK_RETURN(status);
726 status = ndr_table_register(&ndr_table_exchange_nsp);
727 NT_STATUS_NOT_OK_RETURN(status);
729 status = ndr_table_register(&ndr_table_exchange_ds_rfr);
730 NT_STATUS_NOT_OK_RETURN(status);
732 /* Step3. Finally register mapiproxy endpoint */
733 status = dcerpc_server_mapiproxy_init();
734 NT_STATUS_NOT_OK_RETURN(status);
739 /* include server boiler template */
740 #include "gen_ndr/ndr_exchange_s.c"