9101bc64bbd8d00233d03268a6fe99d064c0eabe
[jelmer/openchange.git] / mapiproxy / dcesrv_mapiproxy_server.c
1 /*
2    MAPI Proxy
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2009
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "mapiproxy/dcesrv_mapiproxy.h"
23 #include "mapiproxy/libmapiproxy.h"
24 #include <util/debug.h>
25
26 /**
27    \file dcesrv_mapiproxy_server.c
28
29    \brief mapiproxy server modules management
30  */
31
32 static struct server_module {
33         struct mapiproxy_module *server_module;
34 } *server_modules = NULL;
35
36 int                                     num_server_modules;
37 static struct mapiproxy_module_list     *server_list = NULL;
38
39 static TDB_CONTEXT                      *emsabp_tdb_ctx = NULL;
40
41
42 NTSTATUS mapiproxy_server_dispatch(struct dcesrv_call_state *dce_call,
43                                    TALLOC_CTX *mem_ctx, void *r,
44                                    struct mapiproxy *mapiproxy)
45 {
46         struct mapiproxy_module_list            *server;
47         const struct ndr_interface_table        *table;
48         NTSTATUS                                status;
49
50         table = (const struct ndr_interface_table *)dce_call->context->iface->private;
51
52         for (server = server_list; server; server = server->next) {
53                 if (server->module->endpoint && table->name &&
54                     !strcmp(table->name, server->module->endpoint)) {
55                         if (server->module->dispatch) {
56                                 mapiproxy->norelay = true;
57                                 status = server->module->dispatch(dce_call, mem_ctx, r, mapiproxy);
58                                 NT_STATUS_NOT_OK_RETURN(status);
59                         }
60                 }
61         }
62
63         return NT_STATUS_OK;
64 }
65
66
67 NTSTATUS mapiproxy_server_unbind(struct server_id server_id, uint32_t context_id)
68 {
69         struct mapiproxy_module_list            *server;
70         NTSTATUS                                status;
71
72         for (server = server_list; server; server = server->next) {
73                 if (server->module->unbind) {
74                         status = server->module->unbind(server_id, context_id);
75                         NT_STATUS_NOT_OK_RETURN(status);
76                 }
77         }
78
79         return NT_STATUS_OK;
80 }
81
82
83 extern NTSTATUS mapiproxy_server_register(const void *_server_module)
84 {
85         const struct mapiproxy_module   *server_module = _server_module;
86
87         server_modules = realloc_p(server_modules, struct server_module, num_server_modules + 1);
88         if (!server_modules) {
89                 smb_panic("out of memory in mapiproxy_server_register");
90         }
91
92         server_modules[num_server_modules].server_module = smb_xmemdup(server_module, sizeof (*server_module));
93         server_modules[num_server_modules].server_module->name = smb_xstrdup(server_module->name);
94
95         num_server_modules++;
96
97         DEBUG(3, ("MAPIPROXY server '%s' registered\n", server_module->name));
98
99         return NT_STATUS_OK;
100 }
101
102
103 _PUBLIC_ bool mapiproxy_server_loaded(const char *endpoint)
104 {
105         struct mapiproxy_module_list    *server;
106         
107         if (!endpoint) return false;
108
109         for (server = server_list; server; server = server->next) {
110                 if (server->module->endpoint && !strcmp(endpoint, server->module->endpoint)) {
111                         return true;
112                 }
113         }
114
115         return false;
116 }
117
118
119 static NTSTATUS mapiproxy_server_overwrite(TALLOC_CTX *mem_ctx, const char *name, const char *endpoint)
120 {
121         struct mapiproxy_module_list    *server;
122         struct mapiproxy_module_list    *server_load;
123
124         if (!name) return NT_STATUS_NOT_FOUND;
125         if (!endpoint) return NT_STATUS_NOT_FOUND;
126
127         /* Step 0. Ensure given module matches with endpoint */
128         server_load = talloc_zero(mem_ctx, struct mapiproxy_module_list);
129         server_load->module = mapiproxy_server_byname(name);
130         if (!server_load->module) {
131                 DEBUG(0, ("MAPIPROXY ERROR: couldn't load server '%s'\n", name));
132                 talloc_free(server_load);
133                 return NT_STATUS_NOT_FOUND;
134         } else {
135                 if (strcmp(server_load->module->endpoint, endpoint)) {
136                         DEBUG(0, ("MAPIPROXY ERROR: %s endpoint expected for %s but %s found!\n",
137                                   endpoint, server_load->module->name, server_load->module->endpoint));
138                         talloc_free(server_load);
139                         return NT_STATUS_NOT_FOUND;
140                 }
141         }
142
143         /* Step 1. Seek if this module has already been loaded */
144         for (server = server_list; server; server = server->next) {
145                 if (!strcmp(server->module->name, name) &&
146                     !strcmp(server->module->endpoint, endpoint)) {
147                         DEBUG(0, ("MAPIPROXY: server '%s' already loaded - skipped\n", name));
148                         talloc_free(server_load);
149                         return NT_STATUS_OK;
150                 }
151         }
152
153         /* Step 2. Delete any loaded server matching given endpoint */
154         for (server = server_list; server; server = server->next) {
155                 if (!strcmp(server->module->endpoint, endpoint)) {
156                         DLIST_REMOVE(server_list, server);
157                         talloc_free(server);
158                 }
159         }
160
161         /* Step 3. Load custom server */
162         DLIST_ADD_END(server_list, server_load, struct mapiproxy_module_list *);
163
164         return NT_STATUS_OK;
165 }
166
167
168 static NTSTATUS mapiproxy_server_load(struct dcesrv_context *dce_ctx)
169 {
170         NTSTATUS                                status;
171         struct mapiproxy_module_list            *server;
172         bool                                    server_mode;
173         int                                     i;
174         const char                              *nspi;
175         const char                              *emsmdb;
176         const char                              *rfr;
177         const char                              *server_name[] = { NDR_EXCHANGE_NSP_NAME, 
178                                                                    NDR_EXCHANGE_EMSMDB_NAME,
179                                                                    NDR_EXCHANGE_DS_RFR_NAME, NULL };
180
181         /* Check server mode */
182         server_mode = lp_parm_bool(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "server", false);
183         DEBUG(0, ("MAPIPROXY server mode %s\n", (server_mode == false) ? "disabled" : "enabled"));
184
185         if (server_mode == true) {
186                 DEBUG(0, ("MAPIPROXY proxy mode disabled\n"));
187
188                 for (i = 0; server_name[i]; i++) {
189                         server = talloc_zero(dce_ctx, struct mapiproxy_module_list);
190                         server->module = mapiproxy_server_bystatus(server_name[i], MAPIPROXY_DEFAULT);
191                         if (server->module) {
192                                 DLIST_ADD_END(server_list, server, struct mapiproxy_module_list *);
193                         } else {
194                                 DEBUG(0, ("MAPIPROXY ERROR: couldn't load server '%s'\n", server_name[i]));
195                         }
196                 }
197         }
198
199         /* Check for override/custom NSPI server */
200         nspi = lp_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "nspi_server");
201         mapiproxy_server_overwrite(dce_ctx, nspi, NDR_EXCHANGE_NSP_NAME);
202
203         /* Check for override/custom EMSMDB server */
204         emsmdb = lp_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "emsmdb_server");
205         mapiproxy_server_overwrite(dce_ctx, emsmdb, NDR_EXCHANGE_EMSMDB_NAME);
206
207         /* Check for override/custom RFR server */
208         rfr = lp_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_mapiproxy", "rfr_server");
209         mapiproxy_server_overwrite(dce_ctx, rfr, NDR_EXCHANGE_DS_RFR_NAME);
210
211         for (server = server_list; server; server = server->next) {
212                 DEBUG(3, ("mapiproxy_server_load '%s' (%s)\n", 
213                           server->module->name, server->module->description));
214                 if (server->module->init) {
215                         status = server->module->init(dce_ctx);
216                         NT_STATUS_NOT_OK_RETURN(status);
217                 }
218         }
219
220         return NT_STATUS_OK;
221 }
222
223
224 _PUBLIC_ NTSTATUS mapiproxy_server_init(struct dcesrv_context *dce_ctx)
225 {
226         init_module_fn          *servers;
227         NTSTATUS                ret;
228
229         servers = load_samba_modules(NULL, dce_ctx->lp_ctx, "dcerpc_mapiproxy_server");
230
231         run_init_functions(servers);
232         talloc_free(servers);
233
234         ret = mapiproxy_server_load(dce_ctx);
235
236         return ret;
237 }
238
239
240 const struct mapiproxy_module *mapiproxy_server_bystatus(const char *name, enum mapiproxy_status status)
241 {
242         int     i;
243
244         if (!name) return NULL;
245
246         for (i = 0; i < num_server_modules; i++) {
247                 if ((strcmp(server_modules[i].server_module->name, name) == 0) && 
248                     (server_modules[i].server_module->status == status)) {
249                         return server_modules[i].server_module;
250                 }
251         }
252
253         return NULL;
254 }
255
256
257 const struct mapiproxy_module *mapiproxy_server_byname(const char *name)
258 {
259         int     i;
260
261         if (!name) return NULL;
262
263         for (i = 0; i < num_server_modules; i++) {
264                 if ((strcmp(server_modules[i].server_module->name, name) == 0)) {
265                         return server_modules[i].server_module;
266                 }
267         }
268
269         return NULL;
270 }
271
272
273 /**
274    \details Initialize an EMSABP TDB context available to all
275    instances when Samba is not run in single mode.
276
277    \param lp_ctx pointer to the loadparm context
278
279    \note TDB database can't be opened twice with O_RDWR flags. We
280    ensure here we have a general context initialized, which we'll
281    reopen within forked instances
282
283    return Allocated TDB context on success, otherwise NULL
284  */
285 _PUBLIC_ TDB_CONTEXT *mapiproxy_server_emsabp_tdb_init(struct loadparm_context *lp_ctx)
286 {
287         char                    *tdb_path;
288         TALLOC_CTX              *mem_ctx;
289
290         if (emsabp_tdb_ctx) return emsabp_tdb_ctx;
291
292         mem_ctx = talloc_init("mapiproxy_server_emsabp_tdb_init");
293         if (!mem_ctx) return NULL;
294
295         /* Step 0. Retrieve a TDB context pointer on the emsabp_tdb database */
296         tdb_path = talloc_asprintf(mem_ctx, "%s/%s", lp_private_dir(lp_ctx), EMSABP_TDB_NAME);
297         emsabp_tdb_ctx = tdb_open(tdb_path, 0, 0, O_RDWR|O_CREAT, 0600);
298         talloc_free(tdb_path);
299         if (!emsabp_tdb_ctx) {
300                 DEBUG(3, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, strerror(errno)));
301                 talloc_free(mem_ctx);
302                 return NULL;
303         }
304
305         talloc_free(mem_ctx);
306
307         return emsabp_tdb_ctx;
308 }