Merge in r2334:2407 from trunk
[jelmer/openchange.git] / 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-2010
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 static int dispatch_nbr = 0;
32
33 /**
34    \file dcesrv_mapiproxy.c
35
36    \brief mapiproxy main file
37  */
38
39
40 static NTSTATUS mapiproxy_op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
41 {
42         DEBUG(5, ("mapiproxy::mapiproxy_op_reply\n"));
43         return NT_STATUS_OK;
44 }
45
46 static NTSTATUS mapiproxy_op_connect(struct dcesrv_call_state *dce_call, 
47                                      const struct ndr_interface_table *table,
48                                      const char *binding)
49 {
50         NTSTATUS                                status;
51         struct dcesrv_mapiproxy_private         *private;
52         const char                              *user;
53         const char                              *pass;
54         const char                              *domain;
55         struct cli_credentials                  *credentials;
56         bool                                    acquired_creds = false;
57         bool                                    machine_account;
58
59         DEBUG(5, ("mapiproxy::mapiproxy_op_connect\n"));
60
61         /* Retrieve the binding string from parametric options if undefined */
62         if (!binding) {
63                 binding = lpcfg_parm_string(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "binding");
64                 if (!binding) {
65                         DEBUG(0, ("You must specify a DCE/RPC binding string\n"));
66                         return NT_STATUS_INVALID_PARAMETER;
67                 }
68         }
69
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");
75
76         /* Retrieve private mapiproxy data */
77         private = dce_call->context->private_data;
78
79         if (user && pass) {
80                 DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: Using specified account\n"));
81                 credentials = cli_credentials_init(private);
82                 if (!credentials) {
83                         return NT_STATUS_NO_MEMORY;
84                 }
85
86                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
87                 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
88                 if (domain) {
89                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
90                 }
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);
95                 if (!credentials) {
96                         return NT_STATUS_NO_MEMORY;
97                 }
98                 cli_credentials_set_conf(credentials, dce_call->conn->dce_ctx->lp_ctx);
99                 if (domain) {
100                         cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
101                 }
102                 status = cli_credentials_set_machine_account(credentials, dce_call->conn->dce_ctx->lp_ctx);
103                 if (!NT_STATUS_IS_OK(status)) {
104                         return status;
105                 }
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;
114         } else {
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;
117         }
118
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;
123
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));
128                         return status;
129                 }
130                 
131                 DEBUG(3, ("Using binding %s\n", dcerpc_binding_string(dce_call->context, b)));
132                 
133                 switch (dce_call->pkt.ptype) {
134                 case DCERPC_PKT_BIND:
135                         b->assoc_group_id = dce_call->pkt.u.bind.assoc_group_id;
136                         break;
137                 case DCERPC_PKT_ALTER:
138                         b->assoc_group_id = dce_call->pkt.u.alter.assoc_group_id;
139                         break;
140                 default:
141                         break;
142                 }
143                 
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));
147
148                 if (acquired_creds == false) {
149                         talloc_free(credentials);
150                 }
151
152                 if (!NT_STATUS_IS_OK(status)) {
153                         return status;
154                 }
155                 dce_call->context->assoc_group->id = private->c_pipe->assoc_group_id;
156                 
157         } else {
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);
162                 
163                 if (acquired_creds == false) {
164                         talloc_free(credentials);
165                 }
166
167                 if (!NT_STATUS_IS_OK(status)) {
168                         return status;
169                 }
170                 dce_call->context->assoc_group->id = private->c_pipe->assoc_group_id;
171         }
172
173         private->connected = true;
174
175         DEBUG(5, ("dcerpc_mapiproxy: RPC proxy: CONNECTED\n"));
176
177         return NT_STATUS_OK;
178 }
179
180 static NTSTATUS mapiproxy_op_bind_proxy(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
181 {
182         NTSTATUS                                status = NT_STATUS_OK;
183         const struct ndr_interface_table        *table;
184         struct dcesrv_mapiproxy_private         *private;
185         bool                                    delegated;
186
187         /* Retrieve private mapiproxy data */
188         private = dce_call->context->private_data;
189
190         table = ndr_table_by_uuid(&iface->syntax_id.uuid);
191         if (!table) {
192                 dce_call->fault_code = DCERPC_FAULT_UNK_IF;
193                 return NT_STATUS_NET_WRITE_FAULT;
194         }
195
196         if (dcesrv_call_credentials(dce_call)) {
197                 private->credentials = dcesrv_call_credentials(dce_call);
198                 DEBUG(5, ("dcerpc_mapiproxy: Delegated credentials acquired\n"));
199         }
200
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);
204         }
205
206         return status;
207 }
208
209
210 /**
211    \details This function is called when the client binds to one of
212    the interfaces mapiproxy handles.
213
214    \param dce_call pointer to the session context
215    \param iface pointer to the dcesrv interface structure with
216    function hooks
217    \param if_version the version of the pipe
218
219    \return NT_STATUS_OK on success, otherwise NTSTATUS error
220  */
221 static NTSTATUS mapiproxy_op_bind(struct dcesrv_call_state *dce_call, const struct dcesrv_interface *iface, uint32_t if_version)
222 {
223         struct dcesrv_mapiproxy_private         *private;
224         bool                                    server_mode;
225         char                                    *server_id_printable = NULL;
226         
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);
232
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));
235
236         /* Retrieve server mode parametric option */
237         server_mode = lpcfg_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "server", false);
238
239         /* Initialize private structure */
240         private = talloc(dce_call->context, struct dcesrv_mapiproxy_private);
241         if (!private) {
242                 return NT_STATUS_NO_MEMORY;
243         }
244         
245         private->c_pipe = NULL;
246         private->exchname = NULL;
247         private->server_mode = server_mode;
248         private->connected = false;
249
250         dce_call->context->private_data = private;
251
252         if (server_mode == false) {
253           return mapiproxy_op_bind_proxy(dce_call, iface, if_version);
254         }
255
256         return NT_STATUS_OK;
257 }
258
259
260 /**
261    \details Called when the client disconnects from one of the
262    endpoints managed by mapiproxy.
263
264    \param context pointer to the connection context
265    \param iface pointer to the dcesrv interface structure with
266    function hooks
267  */
268 static void mapiproxy_op_unbind(struct dcesrv_connection_context *context, const struct dcesrv_interface *iface)
269 {
270         struct dcesrv_mapiproxy_private *private = (struct dcesrv_mapiproxy_private *) context->private_data;
271
272         DEBUG(5, ("mapiproxy::mapiproxy_op_unbind\n"));
273
274         mapiproxy_module_unbind(context->conn->server_id, context->context_id);
275         mapiproxy_server_unbind(context->conn->server_id, context->context_id);
276
277         if (private) {
278                 talloc_free(private->c_pipe);
279                 talloc_free(private);
280         }
281
282         talloc_free(context);
283
284         return;
285 }
286
287
288 /**
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
292
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
297
298    \return NT_STATUS_OK on success, other NTSTATUS error
299  */
300 static NTSTATUS mapiproxy_op_ndr_pull(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_pull *pull, void **r)
301 {
302         NTSTATUS                                status;
303         enum ndr_err_code                       ndr_err;
304         const struct ndr_interface_table        *table;
305         uint16_t                                opnum;
306         struct dcesrv_mapiproxy_private         *private;
307
308
309         DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_pull\n"));
310
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;
314
315         dce_call->fault_code = 0;
316
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;
321         }
322
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);
326
327                 if (!NT_STATUS_IS_OK(status)) {
328                         dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
329                         return NT_STATUS_NET_WRITE_FAULT;
330                 }
331         }
332
333         if (opnum >= table->num_calls) {
334                 dce_call->fault_code = DCERPC_FAULT_OP_RNG_ERROR;
335                 return NT_STATUS_NET_WRITE_FAULT;
336         }
337
338         *r = talloc_size(mem_ctx, table->calls[opnum].struct_size);
339         if (!*r) {
340                 return NT_STATUS_NO_MEMORY;
341         }
342
343         /* directly alter the pull struct before it got pulled from ndr */
344         mapiproxy_module_ndr_pull(dce_call, mem_ctx, pull);
345
346         ndr_err = table->calls[opnum].ndr_pull(pull, NDR_IN, *r);
347
348         mapiproxy_module_pull(dce_call, mem_ctx, *r);
349
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;
356         }
357
358         return NT_STATUS_OK;
359 }
360
361
362 /**
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
366
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
371
372    \return NT_STATUS_OK on success, otherwise a NTSTATUS error
373  */
374 static NTSTATUS mapiproxy_op_ndr_push(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct ndr_push *push, const void *r)
375 {
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; */
380         uint16_t                                opnum;
381         /* const char                           *name; */
382
383         DEBUG(5, ("mapiproxy::mapiproxy_op_ndr_push\n"));
384
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;
388
389         /* name = table->calls[opnum].name; */
390         /* call = &table->calls[opnum]; */
391
392         dce_call->fault_code = 0;
393
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)) {
398                         switch (opnum) {
399                         case NDR_NSPIGETPROPS:
400                                 mapiproxy_NspiGetProps(dce_call, (struct NspiGetProps *)r);
401                                 break;
402                         case NDR_NSPIQUERYROWS:
403                                 mapiproxy_NspiQueryRows(dce_call, (struct NspiQueryRows *)r);
404                                 break;
405                         default:
406                                 break;
407                         }
408                 }
409
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)) {
413                         switch (opnum) {
414                         case NDR_RFRGETNEWDSA:
415                                 mapiproxy_RfrGetNewDSA(dce_call, (struct RfrGetNewDSA *)r);
416                                 break;
417                         default:
418                                 DEBUG(0, ("exchange_ds_rfr: OTHER DS-RFR CALL DETECTED!\n"));
419                                 break;
420                         }
421                 }
422         }
423
424         mapiproxy_module_push(dce_call, mem_ctx, (void *)r);
425
426         ndr_err = table->calls[opnum].ndr_push(push, NDR_OUT, r);
427
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;
432         }
433
434         return NT_STATUS_OK;
435 }
436
437
438 /**
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
441    remote endpoint.
442
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
446
447    \return NT_STATUS_OK on success, otherwise NTSTATUS error
448  */
449 static NTSTATUS mapiproxy_op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)
450 {
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;
457         uint16_t                                opnum;
458         const char                              *name;
459         NTSTATUS                                status;
460         int                                     this_dispatch;
461         struct timeval                          tv;
462
463         this_dispatch = dispatch_nbr;
464         dispatch_nbr++;
465
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));
468
469         private = dce_call->context->private_data;
470         table = dce_call->context->iface->private_data;
471         opnum = dce_call->pkt.u.request.opnum;
472
473         name = table->calls[opnum].name;
474         call = &table->calls[opnum];
475
476         mapiproxy.norelay = false;
477         mapiproxy.ahead = false;
478
479         if (!private) {
480                 dce_call->fault_code = DCERPC_FAULT_ACCESS_DENIED;
481                 return NT_STATUS_NET_WRITE_FAULT;
482         }
483
484         DEBUG(5, ("mapiproxy::mapiproxy_op_dispatch: %s(0x%x): %zd bytes\n",
485                   table->calls[opnum].name, opnum, table->calls[opnum].struct_size));
486
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);
490                 }
491
492                 private->c_pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
493         }
494
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;
501                 }
502         } else {
503                 if (table->name && !strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) {
504                         if (opnum == NDR_NSPIDNTOMID) {
505                                 mapiproxy_NspiDNToMId(dce_call, (struct NspiDNToMId *)r);
506                         }
507                 }
508         }
509
510         if (private->server_mode == false) {
511         ahead:
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;
520                         }
521                 }
522                 
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;
527                 }
528                 
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);
532                 }
533                 
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;
539                 }
540                 
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);
544                 }
545                 
546                 if (mapiproxy.ahead == true) goto ahead;
547         }
548
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));
551         
552         return NT_STATUS_OK;
553 }
554
555
556 /**
557    \details Register an endpoint
558
559    \param dce_ctx pointer to the dcerpc context
560    \param iface pointer to the dcesrv interface with function hooks
561
562    \return NT_STATUS_OK on success, otherwise NTSTATUS error
563  */
564 static NTSTATUS mapiproxy_register_one_iface(struct dcesrv_context *dce_ctx, const struct dcesrv_interface *iface)
565 {
566         const struct ndr_interface_table        *table = iface->private_data;
567         int                                     i;
568
569         for (i = 0; i < table->endpoints->count; i++) {
570                 NTSTATUS        ret;
571                 const char      *name = table->endpoints->names[i];
572
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));
576                         return ret;
577                 }
578         }
579
580         return NT_STATUS_OK;
581 }
582
583
584 /**
585    \details Initializes the server and register emsmdb,nspi and rfr
586    interfaces
587
588    \param dce_ctx pointer to the dcesrv context
589    \param ep_server pointer to the endpoint server list
590
591    \return NT_STATUS_OK on success, otherwise NTSTATUS error
592  */
593 static NTSTATUS mapiproxy_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
594 {
595         NTSTATUS                ret;
596         struct dcesrv_interface iface;
597         char                    **ifaces;
598         uint32_t                i;
599         static bool             initialized = false;
600
601         if (initialized == true) return NT_STATUS_OK;
602
603         /* Register mapiproxy modules */
604         ret = mapiproxy_module_init(dce_ctx);
605         NT_STATUS_NOT_OK_RETURN(ret);
606
607         /* Register mapiproxy servers */
608         ret = mapiproxy_server_init(dce_ctx);
609         NT_STATUS_NOT_OK_RETURN(ret);
610
611         ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "interfaces"), NULL);
612
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;
618                 }
619
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]));
623                         return ret;
624                 }
625         }
626
627         initialized = true;
628         return NT_STATUS_OK;
629 }
630
631
632 static bool mapiproxy_fill_interface(struct dcesrv_interface *iface, const struct ndr_interface_table *tbl)
633 {
634         iface->name = tbl->name;
635         iface->syntax_id = tbl->syntax_id;
636         
637         iface->bind = mapiproxy_op_bind;
638         iface->unbind = mapiproxy_op_unbind;
639         
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;
644
645         iface->private_data = tbl;
646
647         return true;
648 }
649
650
651 static bool mapiproxy_op_interface_by_uuid(struct dcesrv_interface *iface, const struct GUID *uuid, uint32_t if_version)
652 {
653         const struct ndr_interface_list *l;
654
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);
659                 }
660         }
661
662         return false;
663 }
664
665
666 static bool mapiproxy_op_interface_by_name(struct dcesrv_interface *iface, const char *name)
667 {
668         const struct ndr_interface_table        *tbl;
669
670         tbl = ndr_table_by_name(name);
671
672         if (tbl) {
673                 return mapiproxy_fill_interface(iface, tbl);
674         }
675
676         return false;
677 }
678
679
680 /**
681    \details register the mapiproxy endpoint server.
682
683    \return NT_STATUS_OK on success, otherwise NTSTATUS error
684  */
685 NTSTATUS dcerpc_server_mapiproxy_init(void)
686 {
687         NTSTATUS                        ret;
688         struct dcesrv_endpoint_server   ep_server;
689
690         ZERO_STRUCT(ep_server);
691
692         /* Fill in our name */
693         ep_server.name = "mapiproxy";
694
695         /* Fill in all the operations */
696         ep_server.init_server = mapiproxy_op_init_server;
697
698         ep_server.interface_by_uuid = mapiproxy_op_interface_by_uuid;
699         ep_server.interface_by_name = mapiproxy_op_interface_by_name;
700
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!"));
705                 return ret;
706         }
707
708         /* Full DCE/RPC interface table needed */
709         ndr_table_init();
710         
711         return ret;
712 }
713
714 /**
715    \details Register mapiproxy dynamic shared object modules
716
717    This function registers mapiproxy modules located
718  */
719
720 /**
721    \details Entry point of mapiproxy dynamic shared object.
722
723    This function first registers exchange endpoints and ndr tables,
724    then attempts to register the mapiproxy interface.
725
726    \return NT_STATUS_OK on success, otherwise NT_STATUS_UNSUCCESSFUL;
727  */
728 NTSTATUS samba_init_module(void)
729 {
730         NTSTATUS status;
731
732         /* Step1. Register Exchange endpoints */
733         status = dcerpc_server_exchange_emsmdb_init();
734         NT_STATUS_NOT_OK_RETURN(status);
735
736         status = dcerpc_server_exchange_nsp_init();
737         NT_STATUS_NOT_OK_RETURN(status);
738
739         status = dcerpc_server_exchange_ds_rfr_init();
740         NT_STATUS_NOT_OK_RETURN(status);
741
742         /* Step2. Register Exchange ndr tables */
743         status = ndr_table_register(&ndr_table_exchange_emsmdb);
744         NT_STATUS_NOT_OK_RETURN(status);
745
746         status = ndr_table_register(&ndr_table_exchange_nsp);
747         NT_STATUS_NOT_OK_RETURN(status);
748
749         status = ndr_table_register(&ndr_table_exchange_ds_rfr);
750         NT_STATUS_NOT_OK_RETURN(status);
751
752         /* Step3. Finally register mapiproxy endpoint */
753         status = dcerpc_server_mapiproxy_init();
754         NT_STATUS_NOT_OK_RETURN(status);
755
756         return NT_STATUS_OK;
757 }
758
759 /* include server boiler template */
760 #include "gen_ndr/ndr_exchange_s.c"